일반 c프로그램에서 errno는 어떻게 작동되나요?
      글쓴이: ceo236 / 작성시간: 수, 2003/07/23 - 1:46오후    
  
  크게 질문 두가지가 있습니다.
1. /usr/include/errno.h 에 errno 에 대한 내용이 없는데, 
(ex) #define EPERM 1 /* Operation not permitted */) 
혹시 다른 헤더파일(*.h) 에 있나요? 
2. 일반 TEST프로그램(pthread함수이용) 을 짜서 컴파일후 실행하는데, 
main() 함수 처음에 errno를 출력해봤는데, 
errno=251(ENOSYS) 가 나옵니다. 뭐가 잘못되었을까요? 
(참고로 컴파일은 cc -o thread_sample thread_sample.c -lpthread 
이렇게 했습니다) 
좀 황당한 질문이죠?
고수님들의 많은 조언 부탁드립니다....
Forums: 


1.errno.h는 일반적으로 /usr/include 에 존재하며, Ex
1.errno.h는 일반적으로 /usr/include 에 존재하며, Exxx 계열의 에러값도
같이 정의되어 있지만, 시스템에 따라 다른 위치에 존재하는 errno.h에
에러값이 정의되는 경우도 있습니다. SunOS를 예로 들자면
/usr/include/sys/errno.h에 에러코드에 대한 정의가 들어있으며,
/usr/include/errno.h에서 위의 헤더화일을 include 하도록 되어있습니다.
( /usr/include/errno.h의 #include 부분을 유심히 살펴보세요..)
2.ENOSYS는(제 경우를 말씀드리자면...) 아직 구현되지 않은 함수를 호출할 때
발생하더군요. 함수 내부적으로 실제적인 작업은 이루어지지 않고 ENOSYS
코드를 셋팅하는 것 같습니다...
s(˘∼˘*)z,·´″"`°³о$ √(´∀`√)... (˘ヘ˘ㆀ)a
Re: 일반 c프로그램에서 errno는 어떻게 작동되나요?
큰 프로그램이 아니라면 테스트프로그램 소스를 올려주시면 보다 좋은
답변이 기다릴지도......
그리고, 전혀 황당하지 않을수도 있겠네요.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
[quote="ceo236"]1. /usr/include/errno.h
errno 문자열내용에 궁금하신거 보면..
에러문자열 출력해주는 함수로는 -_-;
strerror, perror 이 있구요.
perror는 내부적으루 strerror을 부르구요..
에러 메세지에 대한 내용은 기본 헤더에 없구
리눅스소스로 찾아보니까 /usr/lib/libiberty.a 라이브러리 안에 있네요..
struct error_info { const int value; /* The numeric value from <errno.h> */ const char *const name; /* The equivalent symbolic value */ #ifndef HAVE_SYS_ERRLIST const char *const msg; /* Short message about this value */ #endif }; static const struct error_info error_table[] = { #if defined (EPERM) ENTRY(EPERM, "EPERM", "Not owner"), #endif #if defined (ENOENT) ENTRY(ENOENT, "ENOENT", "No such file or directory"), #endif #if defined (ESRCH) ENTRY(ESRCH, "ESRCH", "No such process"), ..... }strerror 가 메크로긴 합니다만 어쨋든 이 error table을 부르네요..
main()함수 처음에 errno를 출력했는데.. 어쩜 그렇게 나오는지 궁금하네요.. -_-a.
윗분 말씀대루 테스트 프로그램을 보여주실수 있나요?
그리구 확인을 위해... 저두 쓰레드샘플사용해서.. -_-a...
gcc -o thread_sample thread_sample.c -lpthread 루 컴파일 했구여..
printf("%d\n",errno);
printf("%s\n",strerror(errno));
결과>
0
Success
중간에 무슨 함수를 불러서
그 함수 안에서 errno를 변경하는게 아닌지 싶은데..
main 바로 뒤에 썼는데두 그런다면 .. ???
왜 그러는지 잘 모르... -_-a;;
1. EPERM을 찾고 싶으면,find /usr/include -
1. EPERM을 찾고 싶으면,
find /usr/include -follow -name '*.h' | xargs grep EPERM
또는
find /usr/include -follow -name 'errno.h' | xargs grep EPERM
을 치시면 되고.
2. main시작후 errno가 이상한 값을 가지는 이유는 초기화된 적이 없기 때문이죠. 그렇다고 초기화를 해 주어야 하느냐.. 그건 아닙니다.
errno는 C library function들이 에러를 돌려줄 때 그 에러가 무엇인지는 알려주지만, error 자체가 발생했는지 여부는 errno만 가지고는 알 수 없습니다.
또한 대부분의 library function들은 error가 발생했을 경우에만 errno를 setting하고 error가 발생하지 않았을 때에는 errno를 건드리지도 않습니다.
fopen()을 예로 들어볼까요? fopen()이 NULL을 리턴하면 error가 발생했다는 것이죠. 이 때 errno에는 에러의 종류가 들어있습니다. 그러나 fopen()이 NULL을 리턴하지도 않았는데 errno를 읽고 그 값을 쓰는 것은 잘못된 것입니다. fopen()이 NULL을 리턴하지 않은 경우 (성공적으로 수행된 경우), errno를 건드리지도 않기 때문이죠.
그럼 이만.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
[quote="cinsk"]2.main시작후 errno가 이상한 값을 가
음.. 한가지 궁금한게 있어서 질문드립니다.
POSIX에서 보통 헤더파일에 extern int errno;
혹은 사용시에 extern int errno;
라고 정의해서 사용하는데
즉. errno는 외부변수로 어디에선가 초기값을 갖거나
설사 초기값을 갖지 않다고 하더라도 자동으로 0으로 초기화 되는거 아닌지요.
왜 그런지좀 알겨주세요-_..
제가 질문한 소스 올립니다.
#include <pthread.h> #include <stdio.h> #include <sys/types.h> /* messag_q */ #include <sys/ipc.h> /* messag_q */ #include <sys/msg.h> /* messag_q */ #include <time.h> #include <errno.h> #include <stdarg.h> #define MAXLINE 4096 #define MESG_KEY (key_t) 0x5757 #define PERMS 0666 #define MAX_BUF_SIZE 1024 #define THREAD_CNT 1 struct { long type; char data[MAX_BUF_SIZE]; } Msg_buf; char templog[MAX_BUF_SIZE]; typedef struct{ int nproc; /* 각 thread 구분 */ int ad_sockfd; char ad_addr[16]; } SHARED_DATA; int mesg_id1, mesg_id2; pthread_t *thread; void *Queue_proc(void *arg); main() { int pid, rc, rcv_cnt, i; SHARED_DATA *Shared_Data_Val; void *retval; printf("first, errno[%d]\n", errno); errno = 0; printf("errno 초기화 => errno[%d]\n", errno); mesg_id1 = msgget(MESG_KEY, PERMS | IPC_CREAT); if(mesg_id1 < 0) err_sys("msgget error : first"); Rtn_mesginfo(mesg_id1); pid = getpid(); Msg_buf.type = 111; memset(Msg_buf.data, 0x00, sizeof(Msg_buf.data)); strncpy(Msg_buf.data, "PROCESS_STATUS_1", 16); rc = msgsnd(mesg_id1, &Msg_buf, strlen(Msg_buf.data), IPC_NOWAIT); if(rc < 0) { memset(templog, 0x00, sizeof(templog)); sprintf(templog, "msgsnd(mesg_id1 = [%d]) ERROR, rc = [%d]\n", mesg_id1, rc); err_sys(templog); } /* 성공 => '0' 실패 : '-1' */ printf("msgsnd rc = [%d], errno[%d]\n", rc, errno); printf("10초를 기다립니다.\n"); printf("pid = [%d]\n", pid); sleep(10); rcv_cnt = 0; thread = (pthread_t *) calloc(THREAD_CNT, sizeof(pthread_t)); Shared_Data_Val = (SHARED_DATA *) calloc(THREAD_CNT, sizeof(SHARED_DATA)); for(i = 0; i < THREAD_CNT; i++) { Shared_Data_Val[i].nproc = i; rc = pthread_create(&thread[i], NULL, Queue_proc, &Shared_Data_Val[i]); /* Queue_proc(retval); */ if (rc != 0) { printf("[%d]pthread_create error[%d] ! i[%d]\n", rc, errno, i); return (-1); } printf("i[%d]번째, pthread_create 완료\n", i); sleep(5); } for(i = 0; i < THREAD_CNT; i++) { rc = pthread_join(thread[i], NULL); if (rc != 0) { printf("[%d]pthread_join error[%d] ! i[%d]\n", rc, errno, i); return (-1); } printf("i[%d]번째, pthread_join 완료\n", i); } printf("프로그램 종료!\n"); exit(0); } /* Q 삭제 */ int Rtn_mesgRM(int id) { int rc; struct msqid_ds Q_info2; rc = msgctl(id, IPC_RMID, &Q_info2); if(rc < 0) { memset(templog, 0x00, sizeof(templog)); sprintf(templog, "msgctl ERROR, rc = [%d]\n", rc); err_sys(templog); } printf("Q 삭제 성공. 식별값(id) = [%d]\n", id); return(0); } int Rtn_mesginfo(int id) { struct msqid_ds Q_info; struct ipc_perm Q_detail; int rc; char s_time[100], r_time[100], c_time[100]; rc = msgctl(id, IPC_STAT, &Q_info); if(rc < 0) { memset(templog, 0x00, sizeof(templog)); sprintf(templog, "msgctl ERROR, rc = [%d]\n", rc); err_sys(templog); } strncpy((char *)&Q_detail, (char *)&Q_info.msg_perm, sizeof(Q_info.msg_perm)); printf("Q_detail(msg_perm)은 다음과 같다.\n"); printf("Q_detail.uid = [%d]\n", Q_detail.uid); printf("Q_detail.gid = [%d]\n", Q_detail.gid); printf("Q_detail.cuid = [%d]\n", Q_detail.cuid); printf("Q_detail.cgid = [%d]\n", Q_detail.cgid); printf("Q_detail.mode = [%d]\n", Q_detail.mode); printf("Q_info.msg_cbytes = [%d]\n", Q_info.msg_cbytes); printf("Q_info.msg_qnum = [%d]\n", Q_info.msg_qnum); printf("Q_info.msg_qbytes = [%d]\n", Q_info.msg_qbytes); printf("Q_info.msg_lspid = [%d]\n", Q_info.msg_lspid); printf("Q_info.msg_lrpid = [%d]\n", Q_info.msg_lrpid); memset(s_time, 0x00, sizeof(s_time)); memset(r_time, 0x00, sizeof(r_time)); memset(c_time, 0x00, sizeof(c_time)); Get_DateTime(Q_info.msg_stime, s_time); printf("Q_info.msg_stime = [%s]\n", s_time); Get_DateTime(Q_info.msg_rtime, r_time); printf("Q_info.msg_rtime = [%s]\n", r_time); Get_DateTime(Q_info.msg_ctime, c_time); printf("Q_info.msg_ctime = [%s]\n", c_time); return(0); } Get_DateTime(time_t my_time, char *S_my_time) { struct tm *tmbuf; memset(S_my_time, 0x00, sizeof(S_my_time)); tmbuf = localtime(&my_time); sprintf(S_my_time, "%4d%02d%02d%02d%02d%02d", tmbuf->tm_year+1900, tmbuf->tm_mon+1, tmbuf->tm_mday, tmbuf->tm_hour, tmbuf->tm_min, tmbuf->tm_sec); } void *Queue_proc(void *arg) { SHARED_DATA Shared_Data_Buf = *(SHARED_DATA *)arg; int rc; FILE *fp; Msg_buf.type = 111; while(1) { memset(Msg_buf.data, 0x00, sizeof(Msg_buf.data)); rc = msgrcv(mesg_id1, &Msg_buf, MAX_BUF_SIZE, Msg_buf.type, IPC_NOWAIT /* | MSG_NOERROR*/); printf("받아온 Msg_buf.data = [%s], rc = [%d], errno[%d]\n", Msg_buf.data, rc, errno); if(rc != -1) { /* 정상으로 msgrcv를 해왔다. */ /*printf("받아온 Msg_buf.data = [%s], rc = [%d]\n", Msg_buf.data, rc);*/ Rtn_mesginfo(mesg_id1); continue; }else if(errno == ENOMSG) { /* Q의 끝을 msg_qnum 또는 ENOMSG 로 확인*/ break; } else { /* ENOMSG 가 아닌 ERROR 발생 */ memset(templog, 0x00, sizeof(templog)); sprintf(templog, "msgrcv(mesg_id1 = [%d]) ERROR, rc = [%d]\n", mesg_id1, rc); /* err_sys(templog); */ break; } } /* while */ return NULL; }그런데, 이 소스를 AIX 와 LINUX에서 컴파일 후 실행 해 보니, main()함수 첫부분 errno 가 '0' 으로 정상으로 찍힙니다.
그런데, HP-UX 에서 실행하니까, 251번 에러가 납니다...
왜 그런지, 정말 궁금합니다. HP-UX 자체 phtread 라이브러리가 잘못되었을까요?
참고로 HP-UX 에서 컴파일은
( cc -D_REENTRANT -D_THREAD_SAFE -D_POSIX_C_SOURCE=199506L -o thread_sample thread_sample.c q_error.o -lpthread ) 라고 했습니다.
노력하는자가 아름답다.
RE:
errno 의 구현은 시스템마다 조금씩 틀립니다.
전역변수일수도 있고, 아닐수도 있답니다.
Linux 상에서의 errno 는 매크로입니다.
정확하게 어디쯤에 선언되어 있는지는 기억이 안나지만,
매크로를 풀어보면,
*__errno_location() 으로 정의되어 있는 것으로 기억합니다.
HP-UX 나 AIX 는 다뤄볼 일이 없어서 어떻게 되어 있는지 모르지만,
main() 의 시작에서의 errno 체크는 의미 없다고 생각이 되네요.
이유는 cinsk 님의 답글중 2번째에 있답니다.
댓글 달기