Quick Reference
assert는 프로그램 내부 전제가 깨졌는지 확인하고, errno는 문서화된 함수 실패 직후 원인을 읽습니다. 사용자 입력·파일·할당 실패는 반환값으로 처리합니다.
assert(ptr != NULL);
FILE *fp = fopen(path, "r");
if (fp == NULL) {
perror("fopen"); /* errno를 바꿀 다른 호출보다 먼저 기록 */
}
errno = 0;
char *end;
long value = strtol(text, &end, 10);
if (errno == ERANGE || end == text || *end != '\0') {
/* 범위·형식 오류 */
}assert는 외부 입력 실패를 복구하는 수단이 아니며 NDEBUG에서는 평가되지 않습니다. errno는 성공 뒤 값에 의미가 없으므로 문서화된 실패 반환을 확인한 직후에만 읽습니다.
역할 구분
이 둘은 모두 실패 주변에서 보이지만 같은 문제를 다루지 않습니다.
assert: 코드 내부 전제가 깨졌는지 본다errno: 함수 호출 실패 원인이 무엇이었는지 본다
assert(ptr != NULL);
assert(index >= 0 && index < count);이건 방어적 런타임 복구 코드가 아니라, 프로그래머의 가정을 즉시 깨뜨리는 용도입니다.
그래서:
- 내부 불변식 점검에는 좋다
- 사용자 입력 오류 처리에는 맞지 않는다
NDEBUG빌드에서는 사라질 수 있다
assert는 <assert.h>, errno와 perror는 <errno.h>와 <stdio.h>, strerror는 <string.h>에서 얻습니다. assert 인자에는 파일 열기, 증가 연산, 할당처럼 제거되면 안 되는 부수 효과를 넣지 않습니다.
실패 처리
FILE *fp = fopen("missing.txt", "r");
if (fp == NULL) {
perror("fopen");
}또는 직접 저장해서 메시지를 만들 수 있습니다.
int saved = errno;
fprintf(stderr, "[%d] %s\n", saved, strerror(saved));여기서 핵심은 "실패를 확인한 직후" 읽는 것입니다. errno를 의미 있게 설정하는 함수 실패 직후가 아니면 이전 값이 남아 있을 수 있고, 다른 함수 호출이 끼면 값이 바뀔 수 있습니다.
성공한 호출 뒤 errno 값은 보통 해석하지 않습니다. strtol처럼 errno로 범위 오류를 알리는 함수는 호출 전에 errno = 0으로 두고, 반환값·end pointer·errno를 함께 검사합니다.
perror는 가장 빠른 출력용이고, strerror(saved)는 직접 메시지를 조합할 때 유용합니다.
선택 기준
- 절대 깨지면 안 되는 내부 가정:
assert - 파일 열기/메모리 할당/시스템 호출 실패 원인 출력:
errno기반 처리 - 사용자 입력/외부 실패 처리: 반환값과 에러 메시지
- 함수 실패 뒤 원인을 로그로 남긴다: 실패를 확인한 직후
errno를 저장
이 둘을 같은 카드에서 같이 보는 이유는 "둘 다 실패 상황 주변에서 보이지만 목적은 다르다"는 점을 구분하기 위해서입니다.
주의할 점
assert(open_file(path) != NULL)처럼 부작용이 있는 표현식을 넣는 습관은 좋지 않습니다. 릴리스 빌드에서 assert가 제거되면 그 호출 자체가 사라질 수 있기 때문입니다.
참고 링크
3 sources