C 라이브러리 함수의 이론적 근거는 errno를 0으로 설정하지 않음


9

C 표준은 C 표준 라이브러리 기능이 errno0으로 설정되어서는 안된다고 규정합니다 . 왜 이것이 정확히입니까?

여러 함수를 호출 errno하고 마지막 함수 이후 에만 확인하는 것이 유용하다는 것을 이해할 수 있습니다 .

errno = 0;
double x = strtod(str1, NULL);
long y = strtol(str2, NULL);
if (errno)
    // either "strtod" or "strtol" failed
else
    // both succeeded

그러나 이것이 "나쁜 습관"으로 간주되지 않습니까? errno맨 끝 에서만 확인하기 때문에 함수 중 하나만 실패했지만 실패한 함수 아님 알고 있습니다. 무엇인가 가 실제적인 프로그램에 충분하지 않다는 것을 아는 입니까?

다양한 C 이론적 문서를 찾으려고 시도했지만 많은 문서에 대한 세부 정보가 없습니다 <errno.h>.


1
나는 그것이 당신이 원하지 않는 것에 대해 돈을 지불하지 않는다고 생각합니다. 에 관심이 있다면 errno언제든지 제로로 설정할 수 있습니다.
Kerrek SB

2
알아 두어야 할 것은 함수가 errno성공하더라도 0이 아닌 값으로 설정할 수 있다는 것입니다 . (실패한 다른 함수를 호출 할 수도 있지만 외부 함수에서는 실패를 구성하지 않습니다.)
Keith Thompson

답변:


10

errno역사적 이유로 1 C 라이브러리는 0으로 설정되지 않습니다 . POSIX는 더 이상 성공할 경우 라이브러리가 값을 변경하지 않을 것이라고 주장하지 않으며 새로운 Linux 매뉴얼 페이지에errno.h 다음 사항이 반영됩니다.

<errno.h>헤더 파일은 정수 변수 정의 errno시스템 호출과 무엇이 잘못되었는지 나타내는 오류의 경우 일부 라이브러리 함수에 의해 설정된다. 이 값은 호출의 리턴 값이 오류를 표시 한 경우 (예 : -1대부분의 시스템 호출 -1또는 NULL대부분의 라이브러리 함수) 에만 중요합니다 . 성공한 함수 변경할 수 있습니다 errno.

ANSI C 이론적 근거는 위원회가 채택 및 사용하는 기존의 관행을 표준화하는 것이 현실적하다고 생각한다고 errno.

설정에 중점을 둔 오류보고 기계 errno는 일반적으로 최대 허용 오차로 간주됩니다. 라이브러리 기능 사이에``병리학 적 커플 링 ''이 필요하고 정적 쓰기 가능 메모리 셀을 사용하여 공유 가능 라이브러리의 구성을 방해합니다. 그럼에도 불구하고,위원회는보다 야심 찬 무언가를 발명하기보다는 기존의 결함이있는 기계를 표준화하는 것을 선호했다.

설정되어 있는지 확인하는 것 이외의 오류를 확인하는 방법은 거의 항상 있습니다 errno. errno일부 호출은 오류 이유를 얻기 위해 별도의 API를 호출해야하므로 설정이 올바른지 확인하는 것이 항상 신뢰할 수있는 것은 아닙니다. 예를 들어, 또는 ferror()에서 짧은 결과를 얻는 경우 오류를 확인하는 데 사용됩니다 .fread()fwrite()

흥미롭게도, 사용의 당신의 예는 strtod()설정 위치를 사례 중 하나입니다 errno통화가되기 전에 0에 필요한 오류가 발생했는지 정확하게 감지 할 수 있습니다. strto*()오류가 발생하더라도 유효한 리턴 값이 리턴되므로 모든 문자열 대 숫자 함수에는이 요구 사항이 있습니다.

errno = 0;
char *endptr;
double x = strtod(str1, &endptr);
if (endptr == str1) {
    /*...parse error */
} else if (errno == ERANGE) {
    if (x == 0) {
        /*...underflow */
    } else if (x == HUGE_VAL) {
        /*...positive overflow */
    } else if (x == -HUGE_VAL) {
        /*...negative overflow */
    } else {
        /*...unknown range error? */
    }
}

위의 코드는 strtod()Linux에 문서화 된 동작을 기반으로합니다 . C 표준은 언더 플로우가 작은 양의보다 큰 값을 반환 할 수 있도록 규정 double하고 있는지의 여부가 errno설정되었습니다 ERANGE구현이 정의 2 .

실제로 라이브러리 호출 전에 항상 0으로 설정 하고 호출이 실패를 표시 한 후 해당 값 확인하도록 권장 하는 광범위한 인증서 권고 작성 있습니다. 일부 라이브러리 호출을 설정하기 때문입니다 호출 자체가 성공하더라도 3 .errnoerrno

errno프로그램 시작시 값 은 0이지만 라이브러리 함수에 의해 0으로 설정되지 않습니다. C 표준의 함수 설명에 errno사용이 errno문서화되어 있지 않은 경우 오류가 있는지 여부에 관계없이 라이브러리 함수 호출에 의해 값이 0이 아닌 값 으로 설정 될 수 있습니다 . 프로그램이 errno오류가보고 된 후에 만 내용을 검사하는 것이 의미 가 있습니다. 보다 정확하게 errnoerrno오류 를 설정하는 라이브러리 함수가 오류 코드를 반환 한 후에 만 의미 가 있습니다.


1. 이전에는 이전 호출의 오류를 가리는 것을 피한다고 주장했습니다. 이 주장을 뒷받침 할 증거를 찾을 수 없습니다. 나는 또한 가짜 printf()예를 가지고있었습니다 .
2. 이것을 지적 해준 @chux에게 감사합니다. 참조는 C.11 §7.22.1.3 ¶10이다.
3. 댓글에서 @KeithThompson이 지적했습니다.


사소한 문제 : 언더 플로로 인해 0이 아닌 결과가 나타날 수 있습니다. "함수는 반환 유형에서 가장 작은 정규화 된 양수보다 크지 않은 값을 반환합니다"C11 7.22.1.3.10.
chux-복원 Monica Monica

@ chux : 감사합니다. 편집하겠습니다. 설정 이후 errnoERANGE언더 플로우의 경우에 구현 정의, 더 언더 실제로 검출하기 이식성이 없다. 내 코드는 내 시스템의 Linux 매뉴얼 페이지에서 찾은 내용을 따랐습니다.
jxh

strto*함수 에 대한 귀하의 의견은 내 예제가 나쁜 습관으로 간주되는지 묻는 이유입니다. 그러나 errno0으로 설정하지 않으면 유용하거나 적용 할 수 있는 유일한 방법입니다 .

@ DrewMcGowen : 당신이 취할 수있는 유일한 포인트 errno는 성공의 경우에도 설정 될 수 있다는 것입니다. 그래서 설정 된 사실을 사용하는 것이 실제로 오류가 발생했다는 충분한 지표가 아닙니다. 개별 호출 결과를 확인하여 오류가 발생했는지 확인해야합니다.
jxh

1

정말로 신경 쓰면 두 함수 호출 모두에 대해 오류 검사를 할 수 있습니다.

errno = 0;
double x = strtod(str1, NULL);
if (errno)
    // strtod"  failed
else
    // "strtod" succeeded

long y = strtol(str2, NULL);
if (errno)
    // "strtol" failed
else
    // "strtol" succeeded

우리는 프로세스에서 mach 함수가 어떻게 호출되는지 알지 못하므로 lib는 각 함수 호출에 대해 errnos를 어떻게 설정할 수 있습니까?


1

오류를 임의로 변경하는 것은 예외를 '잡아 삼키는'것과 유사합니다. 프로그램의 다른 계층을 통해 전파되고 예외적으로 호출자가 어떤 방식 으로든 예외를 잡거나 응답 할 수있는 지점에 도달하기 전에 예외가 발생하기 전에 오류가 발생했습니다. 이 1 세대 오류 처리 전파 패러다임에서 처리, 재정의, 관련이없는 오류로 처리하지 않는 한 errno를 변경하지 않는 것이 중요합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.