62 표준 라이브러리 한눈에 보기
먼저 알아야 할 것
돌아보기
61장에서 표준 라이브러리가 “얇고 오래됐다”고 했고, 표준이 언어 문법만이 아니라 라이브러리 목록과 각 함수의 계약까지 못박는다고 했다. 그러면 헤더는 정확히 몇 개이고, 그 목록은 어떻게 늘어 왔는가?
답. C23 기준으로 서른한 개다. C89가 열다섯으로 시작했고, C95가 와이드 문자 관련 둘을, C99가 아홉을, C11이 다섯을, C23이 몇 개를 더했다. 늘어난 속도가 언어의 변화 속도와 거의 같다는 점이 이 목록의 성격을 말해 준다 — 한 번 들어오면 사실상 영원히 남고, 그래서 들이는 데 오래 걸린다. gets의 장례가 수십 년 걸린 이야기(43장)의 뒷면이다.
이 장의 필요성과 맥락
이 장이 끝나면
이 장에서 답할 질문
- 이 중에 실제로 자주 쓰는 것은 몇 개인가?
62.1 자유 사용과 호스트 — 두 개의 세계
표준은 구현을 두 갈래로 나눈다. 호스트 구현(hosted)은 운영체제 위에서 도는 보통의 환경이고, 자유 사용 구현(freestanding)은 운영체제가 없는 환경 — 펌웨어, 커널, 부트로더 — 이다.
둘의 차이가 곧 헤더 목록의 차이다. 자유 사용 구현이 반드시 제공해야 하는 헤더는 다음뿐이고, 나머지는 있어도 되고 없어도 된다.
| 헤더 | 무엇 | 비고 |
|---|---|---|
<float.h> | 실수 타입의 한계 | 값만 정의 |
<limits.h> | 정수 타입의 한계 | 값만 정의 |
<stdarg.h> | 가변 인자 | 58장 |
<stdbool.h> | bool | C99. C23에서는 사실상 불필요 |
<stddef.h> | size_t·NULL·offsetof | 기본 중의 기본 |
<stdint.h> | 고정 폭 정수 | C99 |
<stdalign.h> | alignas·alignof | C11. C23에서 키워드로 |
<stdnoreturn.h> | noreturn | C11. C23에서 폐기 예정 |
<iso646.h> | and·or 같은 대체 철자 | C95 |
<stdbit.h> | 비트 조작 | C23에서 추가 |
<stdckdint.h> | 검사 산술 | C23에서 추가 |
표 62.1
C23이 이 목록을 늘렸다는 점을 눈여겨볼 만하다. 새로 들어온 둘은 운영체제가 필요 없는 순수 계산이라 자유 사용 환경에서도 제공할 수 있고, 하는 일이 (비트 세기와 넘침 검사) 임베디드에서 특히 요긴하기 때문이다. 목록이 자라는 방향이 “OS 없이도 되는 것”이라는 점도 이 구분의 성격을 보여 준다.
그리고 헤더 하나가 통째로 필수인 것과 그 안의 선언 일부만 필수인 것은 다르다 — 예컨대 <string.h>는 자유 사용 필수가 아니지만, 구현이 그 헤더를 제공한다면 그 안의 계약은 표준을 따라야 한다.
이 목록이 짧다는 사실이 이 책 전체의 배경이다 — 임베디드에서는 printf도, malloc도 당연하지 않다(제12부의 프리스탠딩 이야기가 여기서 시작된다).
62.2 전체 목록
표준이 정한 헤더 전부다. “판”은 그 헤더가 표준에 들어온 판이고, 이 부의 어느 장에서 다루는지도 함께 적었다.
| 헤더 | 판 | 무엇을 담는가 | 이 부에서 |
|---|---|---|---|
<assert.h> | C89 | assert — 계약 위반을 잡는 진단 | 75장 |
<complex.h> | C99 | 복소수 산술 | 73장 |
<ctype.h> | C89 | 문자 분류·변환 | 67장 |
<errno.h> | C89 | 오류 번호 전역 | 75장 |
<fenv.h> | C99 | 부동소수점 환경(반올림·예외) | 73장 |
<float.h> | C89 | 실수 타입의 한계 | 27장·73장 |
<inttypes.h> | C99 | 고정 폭 정수의 서식·변환 | 부록 B·78장 |
<iso646.h> | C95 | 연산자의 대체 철자 | 78장 |
<limits.h> | C89 | 정수 타입의 한계 | 27장 |
<locale.h> | C89 | 로케일 설정 | 67장 |
<math.h> | C89 | 수학 함수 | 73장 |
<setjmp.h> | C89 | 비지역 점프 | 75장 |
<signal.h> | C89 | 신호 처리 | 75장 |
<stdalign.h> | C11 | 정렬 지정·질의 | 78장 |
<stdarg.h> | C89 | 가변 인자 | 58장 |
<stdatomic.h> | C11 | 원자적 연산 | 80장 |
<stdbit.h> | C23 | 비트 조작(자릿수·회전 등) | 78장 |
<stdbool.h> | C99 | bool·true·false | 78장 |
<stdckdint.h> | C23 | 넘침을 검사하는 산술 | 52장·81장 |
<stddef.h> | C89 | size_t·ptrdiff_t·NULL·offsetof | 78장 |
<stdint.h> | C99 | 고정 폭 정수 타입 | 27장·78장 |
<stdio.h> | C89 | 스트림 입출력·파일 | 54·64장 |
<stdlib.h> | C89 | 변환·난수·할당·정렬·프로그램 종료 | 66장 |
<stdnoreturn.h> | C11 | noreturn | 78장 |
<string.h> | C89 | 문자열·메모리 블록 | 65장 |
<tgmath.h> | C99 | 타입 제네릭 수학 함수 | 73장 |
<threads.h> | C11 | 스레드·뮤텍스·조건 변수 | 78장 |
<time.h> | C89 | 시각과 달력 | 74장 |
<uchar.h> | C11 | UTF-16·UTF-32 문자 타입 | 67장 |
<wchar.h> | C95 | 와이드 문자 입출력·문자열 | 67장 |
<wctype.h> | C95 | 와이드 문자 분류 | 67장 |
표 62.2
문. 이 중에 실제로 자주 쓰는 것은 몇 개인가?
답. 대부분의 프로그램은 다섯 안팎으로 산다 — <stdio.h>, <stdlib.h>, <string.h>, <stdint.h>, 그리고 필요에 따라 <math.h>나 <time.h>. 나머지는 “있는 줄 알고 필요할 때 찾아 쓰는” 것들이다. 그래서 이 부의 목표도 암기가 아니라 전체 얼개를 머릿속에 두는 것이다 — 어디쯤에 무엇이 있는지, 그리고 어느 구역이 미끄러운지.
흔한 오해. “표준 라이브러리에 있으면 안전하고 이식성 있는 함수다”
표준에 있다는 것은 어디에나 있다는 뜻이지 안전하다는 뜻이 아니다.gets는 1989년 표준에 들어 있었고 2011년에야 삭제됐다(64장). strncpy는 이름과 달리 안전한 복사 함수가 아니며(65장), atoi는 실패를 알릴 방법이 아예 없다(66장). 심지어 같은 이름의 함수가 로케일에 따라 다르게 동작하기도 한다(67장). 표준 라이브러리를 쓴다는 것은 “검증된 것을 쓴다”가 아니라 “계약이 명시된 것을 쓴다”는 뜻이고, 그 계약을 읽는 일은 여전히 우리 몫이다.실제 사례. 헤더 하나가 부른 사고 — <strings.h>는 표준이 아니다
<string.h>는 표준이지만 <strings.h>(복수형)는 POSIX다. strcasecmp·bzero 같은 함수가 거기 있어서, 이것을 쓴 코드는 Windows에서 컴파일되지 않는다. 반대로 strlcpy·strlcat은 OpenBSD에서 나와 여러 유닉스로 퍼졌지만 표준이 아니었다 — C23에 와서야 비슷한 취지의 함수가 논의됐을 뿐이다. “많이 쓰이니 표준이겠지”라는 짐작이 이식성 사고의 흔한 시작이다.복습 정리
| 기억할 것 | 요지 |
|---|---|
| 헤더 수 | C23 기준 서른한 개. C89의 열다섯에서 자랐다 |
| 자유 사용 | 운영체제 없이 보장되는 것은 열한 개뿐(C23이 둘 추가) |
| 들어오는 속도 | 느리다. 나가는 속도는 더 느리다 |
| 표준 = 안전 | 아니다. 표준 = 계약이 적혀 있다 |
<strings.h> | 표준이 아니다(POSIX). 이름에 속지 않는다 |
표 62.3
얼개를 폈으니 걷는다. 다음 두 장은 가장 많이 쓰고 가장 많이 미끄러지는 구역 — 스트림 입출력이다.