C언어 프로그래밍을 하다 보면 파일이 없거나 메모리가 부족한 등 예기치 못한 오류가 발생합니다. 이때 단순히 "프로그램이 종료되었습니다"가 아니라, 정확히 어떤 오류가 발생했는지 알아야 빠르게 대처할 수 있습니다.
오늘은 C 표준 라이브러리인 <errno.h>를 활용해 시스템 오류를 추적하고 처리하는 방법을 상세히 알아보겠습니다.

1. errno.h란 무엇인가?
errno.h는 실행 중 발생한 마지막 오류의 상태 코드를 담는 전역 변수 errno와 이를 제어하는 함수들을 정의한 헤더 파일입니다.
핵심 변수: errno
- 성격: 시스템 호출이나 라이브러리 함수가 실패할 때 설정되는 정수형 변수입니다.
- 주의사항: 함수 호출이 성공하더라도 이전의 에러 값이 남아있을 수 있습니다. 따라서 함수 실패(NULL 반환 등)가 확인된 직후에만 값을 신뢰해야 합니다.
📊 주요 오류 코드 (POSIX 표준)
가장 자주 접하게 되는 오류 코드들입니다.
| 오류 코드 | 의미 | 설명 |
| ENOENT | No such file or directory | 존재하지 않는 파일/디렉토리 오픈 시 |
| EACCES | Permission denied | 파일 접근 권한이 없을 때 |
| ENOMEM | Cannot allocate memory | malloc 등 메모리 할당 실패 시 |
| EINVAL | Invalid argument | 함수에 잘못된 인자가 전달되었을 때 |
| EBADF | Bad file descriptor | 잘못된 파일 식별자를 사용할 때 |
2. 에러 출력 함수: strerror vs perror
오류 코드 숫자만 봐서는 내용을 알기 어렵습니다. 이를 사람이 읽을 수 있는 문자열로 바꾸는 두 가지 대표적인 방법이 있습니다.
2.1 strerror() - 문자열로 반환받기
strerror(errno)는 에러 번호에 해당하는 설명 문자열을 반환합니다. 로그 파일에 기록하거나 UI에 에러 문구를 표시할 때 유용합니다.
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main() {
FILE *file = fopen("missing_config.txt", "r");
if (file == NULL) {
// 원하는 서식으로 에러 메시지 구성 가능
printf("[ERROR] 로그: %s (코드: %d)\n", strerror(errno), errno);
}
return 0;
}
2.2 perror() - 표준 에러로 즉시 출력하기
perror("사용자 정의 메시지")는 현재 errno 상태를 해석하여 사용자 정의 메시지: 에러 내용 형태로 즉시 표준 에러 출력(stderr)에 뿌려줍니다. 디버깅 시 가장 간편합니다.
#include <stdio.h>
#include <errno.h>
int main() {
FILE *file = fopen("protected.txt", "r");
if (file == NULL) {
perror("파일 열기 실패");
// 출력 예시: 파일 열기 실패: Permission denied
}
return 0;
}
3. 실전 활용: 안전한 동적 메모리 할당 예제
대규모 프로그램에서는 메모리 할당 실패를 반드시 체크해야 합니다. errno를 활용한 표준적인 패턴입니다.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main() {
// 1. 에러 변수 초기화 (권장)
errno = 0;
// 2. 터무니없이 큰 메모리 할당 시도
void *ptr = malloc(1024ULL * 1024 * 1024 * 1024);
if (ptr == NULL) {
// 3. 실패 시 즉시 에러 원인 출력
perror("Memory Allocation Error");
return EXIT_FAILURE;
}
free(ptr);
return EXIT_SUCCESS;
}
4. 💡 실무자를 위한 errno 활용 팁 (SEO 포인트)
- 초기화 습관: 함수 호출 전 errno = 0;으로 초기화하면, 특정 함수 호출에 의해 에러가 발생했는지 더 확실히 알 수 있습니다.
- 멀티스레드 안전성(Thread-Safety): 현대 C 표준(C11 이상) 및 POSIX 환경에서 errno는 스레드 로컬(Thread-local) 변수입니다. 즉, 스레드마다 독립적인 errno를 가지므로 멀티스레드 환경에서도 안전하게 사용할 수 있습니다.
- 성공 시에는 유지됨: 함수가 성공하면 errno를 0으로 덮어쓰지 않는 경우가 많습니다. 반드시 함수의 반환값(NULL, -1 등)을 먼저 확인한 뒤 에러 처리를 하세요.
5. 결론
안정적인 소프트웨어는 '정상 동작'보다 '예외 상황'을 얼마나 잘 처리하느냐에 달려 있습니다. errno.h에서 제공하는 도구들을 활용하면 시스템 내부에서 어떤 문제가 생겼는지 명확히 진단할 수 있습니다.
오늘 배운 perror와 strerror를 적재적소에 활용해 디버깅 시간을 단축해 보세요!
포스팅이 도움이 되셨다면 하트(♥)와 댓글 부탁드립니다!
임베디드 및 시스템 프로그래밍의 더 많은 꿀팁은 'Coding by Head' 블로그의 다른 글을 참고해 주세요.
'Core Programming > C Standard Library: Resource & Performan' 카테고리의 다른 글
| C 표준 라이브러리 vs POSIX 차이점 완벽 정리: fopen과 open의 차이는? (0) | 2025.03.05 |
|---|---|
| C언어 메모리 누수(Memory Leak) 원인과 방지 및 디버깅 도구 총정리 (0) | 2025.03.04 |
| C언어 대소문자 변환: toupper, tolower 함수 완벽 가이드 (0) | 2025.03.02 |
| C언어 ctype.h 완벽 정리: 문자 판별 및 대소문자 변환 함수 예제 (0) | 2025.03.01 |
| C언어 qsort, bsearch 완벽 가이드: 배열 정렬과 이진 탐색 예제 (0) | 2025.02.28 |