Core Programming/C Standard Library: Resource & Performan

C언어 에러 처리 완벽 가이드: errno, strerror, perror 사용법 총정리

임베디드 친구 2025. 3. 3. 10:27
반응형

C언어 프로그래밍을 하다 보면 파일이 없거나 메모리가 부족한 등 예기치 못한 오류가 발생합니다. 이때 단순히 "프로그램이 종료되었습니다"가 아니라, 정확히 어떤 오류가 발생했는지 알아야 빠르게 대처할 수 있습니다.

오늘은 C 표준 라이브러리인 <errno.h>를 활용해 시스템 오류를 추적하고 처리하는 방법을 상세히 알아보겠습니다.

Generated by Gemini AI.


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에 에러 문구를 표시할 때 유용합니다.

C
 
#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)에 뿌려줍니다. 디버깅 시 가장 간편합니다.

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

int main() {
    FILE *file = fopen("protected.txt", "r");
    if (file == NULL) {
        perror("파일 열기 실패"); 
        // 출력 예시: 파일 열기 실패: Permission denied
    }
    return 0;
}

3. 실전 활용: 안전한 동적 메모리 할당 예제

대규모 프로그램에서는 메모리 할당 실패를 반드시 체크해야 합니다. errno를 활용한 표준적인 패턴입니다.

C
 
#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 포인트)

  1. 초기화 습관: 함수 호출 전 errno = 0;으로 초기화하면, 특정 함수 호출에 의해 에러가 발생했는지 더 확실히 알 수 있습니다.
  2. 멀티스레드 안전성(Thread-Safety): 현대 C 표준(C11 이상) 및 POSIX 환경에서 errno는 스레드 로컬(Thread-local) 변수입니다. 즉, 스레드마다 독립적인 errno를 가지므로 멀티스레드 환경에서도 안전하게 사용할 수 있습니다.
  3. 성공 시에는 유지됨: 함수가 성공하면 errno를 0으로 덮어쓰지 않는 경우가 많습니다. 반드시 함수의 반환값(NULL, -1 등)을 먼저 확인한 뒤 에러 처리를 하세요.

5. 결론

안정적인 소프트웨어는 '정상 동작'보다 '예외 상황'을 얼마나 잘 처리하느냐에 달려 있습니다. errno.h에서 제공하는 도구들을 활용하면 시스템 내부에서 어떤 문제가 생겼는지 명확히 진단할 수 있습니다.

오늘 배운 perror와 strerror를 적재적소에 활용해 디버깅 시간을 단축해 보세요!


포스팅이 도움이 되셨다면 하트(♥)와 댓글 부탁드립니다!

임베디드 및 시스템 프로그래밍의 더 많은 꿀팁은 'Coding by Head' 블로그의 다른 글을 참고해 주세요.

https://coding-by-head.tistory.com/

반응형