Menu

C 표준 라이브러리: 알아둘 만한 헤더 지도

표준 헤더가 각각 무엇을 제공하는지 - stdio.h, stdlib.h, string.h, math.h, time.h, ctype.h, limits.h, stdbool.h, stdint.h, assert.h - 짧은 동작 예제와 함께 살펴봅니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

언어로서의 C는 아주 작습니다. 타입, 연산자, 제어 흐름, 함수, 포인터가 전부입니다. C는 출력할 수도, 파일을 읽을 수도, 문자열을 비교할 수도, 메모리를 할당할 수도 없습니다. 그 모든 것이 표준 라이브러리입니다. 규격을 따르는 모든 구현이 함께 제공하는 헤더 모음이죠.

이 페이지는 지도입니다. 각 절은 헤더가 무엇을 위한 것인지 말하고, 짧게 동작하는 예제 하나를 보여주고, 더 자세한 페이지가 있다면 그곳을 가리킵니다.

stdio.h - 입력과 출력

거의 모든 프로그램에서 가장 먼저 포함하는 헤더입니다. printfscanf, FILE 타입과 파일 함수들, 그리고 더 안전한 줄 단위 입력 함수들이 들어 있습니다.

핵심은 이렇습니다. 출력에는 printf, fprintf, sprintf, snprintf. 입력에는 scanf, fscanf, sscanf, fgets, getchar. 파일에는 fopen, fclose, fread, fwrite, fseek. 더 깊은 내용은 printf, scanf, 파일 처리에 있습니다.

기억해둘 규칙 하나: 절대 gets()를 쓰지 마세요. 버퍼의 크기를 알 방법이 없으며 C11에서 표준에서 제거되었습니다. fgets(buf, sizeof buf, stdin)가 그 대체입니다.

stdlib.h - 일반 유틸리티

무엇이든 담는 헤더입니다. 메모리, 변환, 난수, 프로세스 제어, 정렬.

주요 항목: malloc, calloc, realloc, free(동적 메모리 참고). 변환에는 atoi, atof, strtol, strtod - atoi가 조용히 0을 돌려주는 자리에서 실패를 알려주는 strto* 계열을 선호하세요. 그리고 randsrand(난수 참고), exit, abort, getenv, system, qsort/bsearch가 있습니다.

string.h - 문자열과 메모리 블록

C의 문자열은 '\0'으로 끝나는 char 배열이며, 문자열에 대한 모든 연산은 함수 호출입니다.

이 헤더가 버퍼 오버플로의 원천이 되지 않게 하는 두 가지 습관이 있습니다. 항상 목적지의 크기를 알고 있을 것, 그리고 strcmp가 같을 때 0을 돌려준다는 사실을 기억할 것 - if (strcmp(a, b))는 문자열이 다를 때 참입니다. 더 안전한 strncpy/snprintf 패턴은 문자열 함수에서 자세히 다룹니다.

math.h - 수학

sqrt, pow, fabs, floor, ceil, round, fmod, 삼각함수와 로그 계열, 그리고 INFINITYNAN이 있습니다.

링커 플래그가 필요할 수 있는 유일한 헤더입니다. 리눅스에서는 컴파일 명령 끝에 -lm을 붙이지 않으면 링커가 "undefined reference to sqrt"를 보고합니다. 전체 내용은 수학 함수에 있습니다.

time.h - 시계와 날짜

struct tm의 두 가지 오프셋은 누구나 한 번씩 걸립니다. tm_year는 1900년부터 세고, tm_mon은 0부터 시작합니다. time(NULL)srand의 흔한 시드이기도 합니다.

ctype.h - 문자 분류

작지만 보기보다 쓸모가 많습니다. 각 함수는 문자 하나를 받아 예/아니오 질문에 답하거나 대소문자를 변환합니다.

전체 목록은 isalpha, isdigit, isalnum, isspace, isupper, islower, ispunct, isxdigit, isprint, 그리고 touppertolower입니다.

(unsigned char) 캐스트에 주목하세요. 이 함수들은 unsigned char로 표현 가능한 값과 EOF에 대해서만 정의되어 있습니다. 대부분의 시스템에서 그냥 char는 부호가 있으므로, 127을 넘는 바이트는 음수로 전달되고 호출은 미정의 동작이 됩니다. 캐스트는 비용이 전혀 없으면서 이 부류의 문제를 통째로 없앱니다.

그리고 직접 만든 검사보다 이들을 선호하세요. c >= '0' && c <= '9'도 우연히 동작하긴 하지만, isdigit(c)는 의도를 말해주고 어디서나 올바르게 동작합니다.

limits.h와 float.h - 타입의 경계

이 기계에서 int는 얼마나 커질 수 있을까요? 이 헤더들이 답해주며, 이식 가능한 코드가 가정하지 않고 물어보는 이유가 바로 그 답에 있습니다.

INT_MAX는 오버플로가 일어나기 전에 확인하는 방법입니다. 부호 있는 오버플로는 나중에 검사할 수 있는 순환이 아니라 미정의 동작이기 때문에 이 점이 중요합니다.

stdbool.h와 stdint.h - 더 나은 타입

C에는 C99 이전까지 불리언 타입이 없었습니다. <stdbool.h>가 하나를 제공합니다.

bool, true, false는 각각 _Bool, 1, 0에 대한 매크로일 뿐이지만 의도를 분명하게 만들어 줍니다. (C23에서는 키워드가 되어 이 헤더가 더 이상 필요하지 않습니다.)

<stdint.h>는 폭이 보장된 타입을 제공합니다. 파일 형식, 네트워크 프로토콜, 그리고 "int는 아마 32비트겠지"로는 충분하지 않은 임베디드 영역에서 필수입니다.

<inttypes.h>PRId32 같은 매크로는 현재 플랫폼에서 각 고정 폭 타입에 맞는 printf 지정자로 확장됩니다. %d는 어떤 시스템에서는 int32_t에 맞고 다른 시스템에서는 틀리기 때문에, 이 매크로가 이식 가능하게 출력하는 방법입니다.

assert.h - 가정 검사하기

assert(expr)는 식이 참이면 아무것도 하지 않고, 거짓이면 메시지를 내고 프로그램을 중단시킵니다.

-DNDEBUG로 컴파일하면 모든 단언문이 제거되므로 릴리스 빌드에서는 비용이 0입니다. 그것이 동시에 경고이기도 합니다. 단언문 안에 부수 효과를 절대 넣지 마세요. assert(read_next() > 0)는 릴리스 빌드에서 읽기 자체를 통째로 멈추게 하고, 그 결과로 생긴 버그는 프로덕션에서만 나타납니다.

단언문은 여러분의 실수를 위한 것입니다. 코드가 올바르다면 불가능해야 하는 조건 말이죠. 잘못된 사용자 입력은 단언문이 아닙니다. 그건 if와 오류 메시지의 몫입니다.

나머지, 간단히

  • <stddef.h> - size_t, ptrdiff_t, NULL, offsetof
  • <stdarg.h> - 가변 인자 함수, printf 뒤의 장치
  • <errno.h> - errno와 함께, 호출이 왜 실패했는지 보고하는 perrorstrerror
  • <signal.h> - Ctrl-C 같은 시그널 처리
  • <setjmp.h> - 비지역 점프. 정답인 경우가 드뭅니다
  • <locale.h>, <wchar.h>, <wctype.h> - 로케일과 와이드 문자
  • <stdnoreturn.h>, <stdalign.h>, <threads.h>, <stdatomic.h> - C11에서 추가된 것들

두 가지 습관이 이 라이브러리를 쓰기 좋게 만듭니다. 시그니처를 추측하기 전에 매뉴얼 페이지를 읽으세요 - macOS와 리눅스의 man 3 strtol은 정확하고 빠릅니다. 그리고 반환값을 확인하세요. malloc, fopen, strtol은 모두 실패를 알려주며, 이를 무시하는 프로그램은 훨씬 나중에, 훨씬 알아보기 어렵게 실패합니다.

자주 묻는 질문

C 표준 라이브러리란 무엇인가요?

규격을 따르는 모든 C 구현이 제공하는 함수, 타입, 매크로의 집합으로, 약 30개의 헤더로 묶여 있습니다. 입출력(<stdio.h>), 메모리와 변환(<stdlib.h>), 문자열(<string.h>), 수학(<math.h>), 시간, 문자 분류, 숫자 타입의 한계까지 다룹니다. C 언어 자체에는 입출력도 문자열 처리도 없습니다. 전부 여기서 옵니다.

stdio.h와 stdlib.h의 차이는 무엇인가요?

<stdio.h>는 입출력입니다. printf, scanf, fopen, fgets, FILE이 들어 있습니다. <stdlib.h>는 일반 유틸리티입니다. mallocfree, atoistrtol, randsrand, exit, qsort, bsearch가 있습니다. 보통의 프로그램은 둘 다 포함합니다.

ctype.h는 무엇을 하나요?

문자 하나를 분류하고 변환합니다. isdigit, isalpha, isalnum, isspace, isupper, islower, ispunct에 더해 touppertolower가 있습니다. c >= '0' && c <= '9' 같은 직접 작성한 비교 대신 이들을 쓰면 의도가 분명해지고 모든 로케일과 문자 집합에서 올바르게 동작합니다.

C 표준 라이브러리를 쓰려면 별도로 링크해야 하나요?

아니요, 다만 수학 함수 하나는 예외입니다. 표준 C 라이브러리는 자동으로 링크되지만, 리눅스에서는 <math.h>의 구현이 별도 라이브러리에 있어서 sqrt 같은 함수에는 컴파일 명령 끝에 -lm이 필요합니다. 나머지는 올바른 #include만 있으면 됩니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기