strerror_r함수에 관하여

bluesoho의 이미지

man에서 찾아보면 char *strerror_r(int errnum, char *buf, size_t len)라고 적혀있었습니다
그런데 아래와 같이 사용하니 buf엔 아무것도 없었습니다
왜 그런지 가르쳐주시면 고맙겠습니다

#include <stdio.h>
#include <errno.h>
#include <string.h>

char buf[256], *perr;

perr = strerror_r(EIO, buf, sizeof(buf));
if(perr)
{
printf("EIO Message: %s\n", perr); /* EIO Message: Input/output error*/
printf("EIO Message: %s\n", buf); /* EIO Message: */
printf("buf length: %d\n", strlen(buf)); /* buf length: 0 */
}

저의 리눅스 환경은 Fedora Core 2, GCC 3.3.3 입니다

hwang의 이미지

buf는 strerror_r함수가 필요할때 사용할수있도록 넘겨주는
것입니다. 필요없으면 사용하질않고 또한 사용한다고 해도
그 안에 의미가 있는 데이타가 들어있다는 보장은 없습니다.

bluesoho의 이미지

hwang wrote:
buf는 strerror_r함수가 필요할때 사용할수있도록 넘겨주는
것입니다. 필요없으면 사용하질않고 또한 사용한다고 해도
그 안에 의미가 있는 데이타가 들어있다는 보장은 없습니다.

아래의 내용은 저의 컴에서 copy해 온 것 입니다
이내용에 따르면 buf에 에러 메시지를 넣는다고 한것 같은데...
만약 그렇지 않다면 이 함수와 strerror()가 뭐가 다릅니까?
잘 이해되지 않습니다.
더 심입된 지도를 바랍니다.
고맙습니.

SYNOPSIS
#include <string.h>

char *strerror(int errnum);
int strerror_r(int errnum, char *buf, size_t n);

DESCRIPTION
The strerror() function returns a string describing the error code
passed in the argument errnum, possibly using the LC_MESSAGES part of
the current locale to select the appropriate language. This string
must not be modified by the application, but may be modified by a sub-
sequent call to perror() or strerror(). No library function will mod-
ify this string.

The strerror_r() function is similar to strerror(), but is thread safe.
It returns the string in the user-supplied buffer buf of length n.

RETURN VALUE
The strerror() function returns the appropriate error description
string, or an unknown error message if the error code is unknown. The
value of errno is not changed for a successful call, and is set to a
nonzero value upon error. The strerror_r() function returns 0 on suc-
cess and -1 on failure, setting errno.

ERRORS
EINVAL The value of errnum is not a valid error number.

ERANGE Insufficient storage was supplied to contain the error descrip-
tion string.

CONFORMING TO
SVID 3, POSIX, BSD 4.3, ISO/IEC 9899:1990 (C89).
strerror_r() with prototype as given above is specified by SUSv3, and
was in use under Digital Unix and HP Unix. An incompatible function,
with prototype

char *strerror_r(int errnum, char *buf, size_t n);

is a GNU extension used by glibc (since 2.0), and must be regarded as
obsolete in view of SUSv3. The GNU version may, but need not, use the
user-supplied buffer. If it does, the result may be truncated in case
the supplied buffer is too small. The result is always NUL-terminated.

SEE ALSO
errno(3), perror(3), strsignal(3)

2001-10-16 STRERROR(3)

hwang의 이미지

strerror함수는 glibc의 경우 strerror_r을 결국 호출합니다.
그때 사용하는 buf가 모든 strerror에서 같이 사용되기때문에
thread unsafe하게됩니다.
strerror_r의 return값이 이미 있는 constant string이라면
굳이 인자로 넘어왔던 buf를 사용하지않아도 아무 문제가 안됩니다.
그럴 경우 buf는 아무런 사용도 하지않은채 그냥 돌려줍니다.

markboy의 이미지

manpage에 해답이 다 나와있습니다. :)

Quote:
int strerror_r(int errnum, char *buf, size_t n);

strerror_r 함수 리턴값은 int 형입니다.

Quote:
The strerror_r() function returns 0 on success and -1 on failure, setting errno.

성공하면 0 실패하면 -1을 반환합니다.

char buf[256], *perr;

perr = strerror_r(EIO, buf, sizeof(buf));
if(perr) 

이 코드를

char buf[256];
int ret_err;

ret_err = strerror_r(EIO, buf, sizeof(buf));
if(0 == ret_err) 

이런식으로 바꾸시면 됩니다.

pynoos의 이미지

char *
__strerror_r (int errnum, char *buf, size_t buflen) 
{
  if (errnum < 0 || errnum >= _sys_nerr || _sys_errlist[errnum] == NULL)
    {
      /* Buffer we use to print the number in.  For a maximum size for
         `int' of 8 bytes we never need more than 20 digits.  */
      char numbuf[21];
      const char *unk = _("Unknown error ");
      const size_t unklen = strlen (unk);
      char *p, *q; 

      numbuf[20] = '\0'; 
      p = _itoa_word (errnum, &numbuf[20], 10, 0); 

      /* Now construct the result while taking care for the destination
         buffer size.  */
      q = __mempcpy (buf, unk, MIN (unklen, buflen));
      if (unklen < buflen) 
        memcpy (q, p, MIN ((size_t) (&numbuf[21] - p), buflen - unklen));

      /* Terminate the string in any case.  */
      if (buflen > 0)
        buf[buflen - 1] = '\0'; 

      return buf;
    }

  return (char *) _(_sys_errlist[errnum]);
}

뭔지 모를 때는 소스를 보는게 제일이죠. 위 코드는 glibc 2.2.2 에서 얻은 것입니다.

잘보니, 인자로 넘겨 받는 버퍼는 Unknown error 4294967293 뭐 이런식으로 출력하는데 쓰이는 군요. errno 값을 음수로 넣어보시면 효과가 나타납니다.

본디 strerror 값은 readonly 이기 때문에 thread safety, reentrant가 보장될 것 같습니다. 다만, unknown error를 출력할 때 맨 뒤에 붙는 에러코드가 고민되는 상황이 되는 군요. 이 경우에만 buf를 사용하며, 그 때는 buf가 의미 있게 쓰이는 군요.

어쨌거나 return 값이 중요한 것이지 buf 는 내부에서만 사용하고 다른 용도(값을 받는)로는 더 사용하지 않습니다.

bluesoho의 이미지

고맙습니다

markboy의 이미지

재미있는 점은 manpage 내용과 실제 헤더에 선언된 내용이 다르다는 점입니다.

manpage에는

int strerror_r(int errnum, char *buf, size_t n);

그런데 /usr/include/string.h 파일을 보면

extern char *strerror_r (int __errnum, char *__buf, size_t __buflen) __THROW;

로 나옵니다. return type이 다르죠. :)

어느쪽이 실제 표준에 맞는 건가요?

덧) debian sid, libc-2.3.2.ds1-13 버전이 설치된 시스템에서 확인했습니다.

singlet의 이미지

실은 info 페이지의 내용과 man 페이지의 내용도 일치하지 않습니다. :)
(제 시스템은 Fedora Core 1, 기본설정 그대로입니다.)

info 페이지 쪽의 내용이 헤더와 일치하더군요.

pynoos의 이미지

strerror_r 의 type이 다르다고만 생각하시는데, 아래 인용한 처음 man page에 두 개의 format이 다 나와 있으며, 각각 어떤 OS에서 사용하는지도 아주 친절하게 설명되어 있습니다.

UNIX에는 이런 류의 함수들이 수도 없이 많습니다. 이름은 같지만 인자나 return 값이 다른 것들 많죠..
gethostbyname_r 같은 함수는 인자를 받는 것이 UNIX 세계에서 무려 세 종류나 됩니다. ( http://www.gnu.org/software/ac-archive/htmldoc/ac_caolan_func_which_gethostbyname_r.html )

이런 것들 때문에 autoconf 라는 좋은 툴이 있습니다. 위의 예에 대한 것들은

http://www.gnu.org/software/autoconf/manual/autoconf-2.57/html_node/autoconf_46.html

여기에서 찾아 보세요.

그리고 이런 종류의 autoconf 매크로는

http://www.gnu.org/software/ac-archive/htmldoc/index.html

에서 거의 다 찾을 수 있습니다.

Quote:

CONFORMING TO
SVID 3, POSIX, BSD 4.3, ISO/IEC 9899:1990 (C89).
strerror_r() with prototype as given above is specified by SUSv3, and
was in use under Digital Unix and HP Unix. An incompatible function,
with prototype

char *strerror_r(int errnum, char *buf, size_t n);

is a GNU extension used by glibc (since 2.0), and must be regarded as
obsolete in view of SUSv3. The GNU version may, but need not, use the
user-supplied buffer. If it does, the result may be truncated in case
the supplied buffer is too small. The result is always NUL-terminated.

singlet의 이미지

man page 에 두 가지가 모두 등장하는 건 알고 있습니다. :) 다만 그 중 SYNOPSIS 에 등장하는 형식이 정작 시스템 상에서는 사용할 수 없는 형식이었다는 점이 문제죠. DESCRIPTION 역시 int 를 반환하는 strerror_r() 함수에 대한 설명이었기 때문에 역시 시스템 상에서는 맞지 않았고요.

pynoos 님은 man page 에 친절하게 설명돼있다고 하셨습니다만, 예를 들어 제 경우같은 초보자 수준에서는 SYNOPSIS 에 나온 형식이 틀려버리면 아주 당황스러운데다 man page 가 그다지 친절하게 읽히지도 않습니다. 정작 둘 중 어느 쪽을 써야 하는 건지, char * 를 반환하는 함수의 경우에 buf 는 뭐에다 쓰는 건지는 man page 만으로는 알 수가 없으니까요. 물론 소스를 뒤져보거나 하면 어렵지 않게 확인할 수 있겠습니다만, 드는 시간도 시간이려니와 처음 접하는 사람에게는 흔히 무리죠.

그러니 뭔가 이상할 경우에는 man page 말고도 info 를 써서 찾아보는 것도 좋다고 생각해서 적어둔 겁니다. man page 가 틀렸으니 믿지 말라는 얘기는 아닙니다. :)

pynoos의 이미지

망할 놈의(?) man page 군요. 우째 자기가 제공하는 것을 보이지 않고 남의 prototype을 보인답니까... 원..

그리고 이런 괴리는 Redhat 9 부터 인것 같네요. 제 7.1 에서는

STRERROR(3)          리눅스 프로그래머 매뉴얼         STRERROR(3)

이름
       strerror - 에러 코드를 설명하는 문자열을 반환한다.

사용법
       #include <string.h>

       char *strerror(int errnum);

설명
       strerror()  함수는 인자 errnum에 전달되는 에러 코드를 설명하는 문자열을 반환한다. 이 문자열은 strerror()에 대한
       다음 호출때까지 사용될수 있다.

반환값
       strerror() 함수는 적당한 설명  문자열을  반환하거나  만일  알지  못하는  에러코드라면  unknown  error  메세지를
       반환한다.

호환
       SVID 3, POSIX, BSD 4.3, ISO 9899

관련 항목
       errno(3), perror(3), strsignal(3)

역자
       정강훈 <skyeyes@soback.kornet.net>, 2001년 2월 24일

GNU                      1993년 4월 13일                        1

확인한 바에 의하면 redhat 9에 있는 glibc 2.3.2 에서 조차 glibc 2.2.x 에 있는 것과 동일한 코드를 사용합니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.