在glibc中會去偵錯並且回傳錯誤值,通常我們都應該去檢查這些回傳值,並且作error-handling,比如開檔 open()/fopen(),並非每次都會開成功,所以,open()/fopen()通常都會去檢查return value是不是有正確。
2.1 Checking for Errors
glibc的return value通常是-1、NULL或是EOF,這只能知道錯誤發生,至於發生何種錯誤,都是存在errno這個變數中,當您要使用errno必須include <errno.h>。這個header file也定義很多error code,都是以E為開頭,這些error code在Ch 2.2中有說明,用到再查就OK啦。
2.2 Error Codes
這個章節主要說明定義的error code,值得注意的是EAGAIN和EWOULDBLOCK的值一樣,所以不能放在同一個case switch中,其實我常用的error code大概只有他列的1/5不到吧,看看就好。
2.3 Error Messages
基本上我們都是希望report的錯誤是文字型態,而不是只有error code,所以glibc有提供一些轉換的function:
char * strerror(int errnum) | [Function] |
char * strerror_r(int errnum, char *buf, size t n) | [Function] |
void perror(const char *message) | [Function] |
char * program_invocation_name | [Variable] |
char * program_invocation_short_name | [Variable] |
void error (int status, int errnum, const char *format, . . . ) | [Function] |
error_at_line (int status, int errnum, const char *fname,unsigned int lineno, const char *format, . . . ) | [Function] |
char * strerror(int errnum)
將errnum轉成相對應的字串
#include <stdio.h>
#include <errno.h> // EINTR
#include <string.h> // strerror()
int main(int argc, char *argv[])
{
printf("%s\n", strerror(EINTR));
// print out "Interrupted system call"
return 0;
}
char * strerror_r(int errnum, char *buf, size t n)
strerror的reentrant版本,mutli-thread就一定要用這個版本。
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h> // EINTR
#include <string.h> // strerror()
int main(int argc, char *argv[])
{
char buf[32];
printf("%s\n", strerror_r(EINTR, buf, sizeof(buf)));
// print out "Interrupted system call"
return 0;
}
void perror(const char *message)
效果和printf(stderr, "%s:%s", message, strerror(errno))相似,把error message寫到stderr去,接著冒號後面再接errno的message。
#include <stdio.h>
#include <errno.h> // EINTR
#include <string.h> // strerror()
int main(int argc, char *argv[])
{
perror("my_perror_msg1");
// print out "my_perror_msg1: Success"
errno = EINTR;
perror("my_perror_msg2");
// print out "my_perror_msg2: Interrupted system call"
return 0;
}
char * program_invocation_name / char * program_invocation_short_name
該程式的名稱,和argv[0]的值一樣。
#include <stdio.h>
#include <errno.h> // EINTR
#include <string.h> // strerror()
int main(int argc, char *argv[])
{
printf("%s\n", argv[0]);
// print out "./a.out"
printf("%s\n", program_invocation_name);
// print out "./a.out"
printf("%s\n", program_invocation_short_name);
// print out "a.out"
return 0;
}
void error (int status, int errnum, const char *format, . . . )
status不為0時,就等同exit(status),後面的參數errnum和format用途類似perror(),當errnum為0時,就不會印後面的message,但是perror()會印Success。
#include <stdio.h>
#include <errno.h> // EINTR
#include <string.h> // strerror()
int main(int argc, char *argv[])
{
error(0, 0, "%s", "msg");
error(0, EINTR, "%s", "msg");
// print out "./a.out: msg: Interrupted system call"
error(1, EINTR, "%s", "msg");
// print out "./a.out: msg: Interrupted system call" and exit(1)
return 0;
}
error_at_line(int status, int errnum, const char *fname, unsigned int lineno, const char *format, ...)
error_at_line()和error()很像,只是多了fname和lineno印出檔案名稱和行號。
#include <stdio.h>
#include <errno.h> // EINTR
#include <string.h> // strerror()
int main(int argc, char *argv[])
{
error_at_line(0, 0, __FILE__, __LINE__, "%s", "msg");
// print out "./a.out:error_at_line.c:7: msg"
error_at_line(0, EINTR, __FILE__, __LINE__, "%s", "msg");
// print out "./a.out:error_at_line.c:8: msg: Interrupted system call"
error_at_line(1, EINTR, __FILE__, __LINE__, "%s", "msg");
// print out "./a.out:error_at_line.c:11: msg: Interrupted system call"
return 0;
}
參考資料:
- The GNU C Library, Chapter 2