일반 c프로그램에서 errno는 어떻게 작동되나요?

ceo236의 이미지

크게 질문 두가지가 있습니다.

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
이렇게 했습니다)

좀 황당한 질문이죠?

고수님들의 많은 조언 부탁드립니다....

xjiwoox의 이미지

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

mach의 이미지

ceo236 wrote:
크게 질문 두가지가 있습니다.

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
이렇게 했습니다)

좀 황당한 질문이죠?

고수님들의 많은 조언 부탁드립니다....


큰 프로그램이 아니라면 테스트프로그램 소스를 올려주시면 보다 좋은
답변이 기다릴지도......
그리고, 전혀 황당하지 않을수도 있겠네요.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

cskblue의 이미지

ceo236 wrote:
1. /usr/include/errno.h 에 errno 에 대한 내용이 없는데,
(ex) #define EPERM 1 /* Operation not permitted */)
혹시 다른 헤더파일(*.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을 부르네요..

ceo236 wrote:
2. 일반 TEST프로그램(pthread함수이용) 을 짜서 컴파일후 실행하는데,
main() 함수 처음에 errno를 출력해봤는데,
errno=251(ENOSYS) 가 나옵니다. 뭐가 잘못되었을까요?
(참고로 컴파일은 cc -o thread_sample thread_sample.c -lpthread
이렇게 했습니다)

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;;

cinsk의 이미지

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를 건드리지도 않기 때문이죠.

그럼 이만.

cskblue의 이미지

cinsk wrote:
2.main시작후 errno가 이상한 값을 가지는 이유는 초기화된 적이 없기 때문이죠

음.. 한가지 궁금한게 있어서 질문드립니다.
POSIX에서 보통 헤더파일에 extern int errno;
혹은 사용시에 extern int errno;
라고 정의해서 사용하는데
즉. errno는 외부변수로 어디에선가 초기값을 갖거나
설사 초기값을 갖지 않다고 하더라도 자동으로 0으로 초기화 되는거 아닌지요.

왜 그런지좀 알겨주세요-_..

ceo236의 이미지

#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 ) 라고 했습니다.

노력하는자가 아름답다.

kslee80의 이미지

errno 의 구현은 시스템마다 조금씩 틀립니다.
전역변수일수도 있고, 아닐수도 있답니다.

Linux 상에서의 errno 는 매크로입니다.
정확하게 어디쯤에 선언되어 있는지는 기억이 안나지만,
매크로를 풀어보면,
*__errno_location() 으로 정의되어 있는 것으로 기억합니다.

HP-UX 나 AIX 는 다뤄볼 일이 없어서 어떻게 되어 있는지 모르지만,
main() 의 시작에서의 errno 체크는 의미 없다고 생각이 되네요.
이유는 cinsk 님의 답글중 2번째에 있답니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.