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