Proven C BookEnglish GitHub

62 표준 라이브러리 한눈에 보기

먼저 알아야 할 것

61장 표준 라이브러리의 지형 · 표준 라이브러리의 성격

돌아보기

61장에서 표준 라이브러리가 “얇고 오래됐다”고 했고, 표준이 언어 문법만이 아니라 라이브러리 목록과 각 함수의 계약까지 못박는다고 했다. 그러면 헤더는 정확히 몇 개이고, 그 목록은 어떻게 늘어 왔는가?

답. C23 기준으로 서른한 개다. C89가 열다섯으로 시작했고, C95가 와이드 문자 관련 둘을, C99가 아홉을, C11이 다섯을, C23이 몇 개를 더했다. 늘어난 속도가 언어의 변화 속도와 거의 같다는 점이 이 목록의 성격을 말해 준다 — 한 번 들어오면 사실상 영원히 남고, 그래서 들이는 데 오래 걸린다. gets의 장례가 수십 년 걸린 이야기(43장)의 뒷면이다.

이 장의 필요성과 맥락

61장이 성격이었다면 이 장은 목록이다. 정독을 시작하기 전에 전체 표를 한 번 펴 두는 것은 길잡이 없이 스물한 장을 걷지 않기 위해서다. 어느 헤더가 어느 판에서 들어왔는지, 운영체제 없이도 쓸 수 있는 것은 무엇인지 — 이 두 축이 뒤의 모든 장에서 되풀이 쓰인다.

이 장이 끝나면

C 표준이 정한 헤더를 하나도 빠뜨리지 않고 표로 편다. 어느 헤더가 어느 판에서 들어왔는지, 운영체제 없이도 쓸 수 있는 것은 무엇인지, 그리고 이 부의 나머지 장들이 어떤 순서로 그 구역들을 걷는지까지. 61장의 지형도를 축척을 키워 다시 그리는 장이다.

이 장에서 답할 질문

  1. 이 중에 실제로 자주 쓰는 것은 몇 개인가?

62.1 자유 사용과 호스트 — 두 개의 세계

표준은 구현을 두 갈래로 나눈다. 호스트 구현(hosted)은 운영체제 위에서 도는 보통의 환경이고, 자유 사용 구현(freestanding)은 운영체제가 없는 환경 — 펌웨어, 커널, 부트로더 — 이다.

둘의 차이가 곧 헤더 목록의 차이다. 자유 사용 구현이 반드시 제공해야 하는 헤더는 다음뿐이고, 나머지는 있어도 되고 없어도 된다.

헤더무엇비고
<float.h>실수 타입의 한계값만 정의
<limits.h>정수 타입의 한계값만 정의
<stdarg.h>가변 인자58장
<stdbool.h>boolC99. C23에서는 사실상 불필요
<stddef.h>size_t·NULL·offsetof기본 중의 기본
<stdint.h>고정 폭 정수C99
<stdalign.h>alignas·alignofC11. C23에서 키워드로
<stdnoreturn.h>noreturnC11. 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>C89assert — 계약 위반을 잡는 진단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>C99bool·true·false78장
<stdckdint.h>C23넘침을 검사하는 산술52장·81장
<stddef.h>C89size_t·ptrdiff_t·NULL·offsetof78장
<stdint.h>C99고정 폭 정수 타입27장·78장
<stdio.h>C89스트림 입출력·파일54·64장
<stdlib.h>C89변환·난수·할당·정렬·프로그램 종료66장
<stdnoreturn.h>C11noreturn78장
<string.h>C89문자열·메모리 블록65장
<tgmath.h>C99타입 제네릭 수학 함수73장
<threads.h>C11스레드·뮤텍스·조건 변수78장
<time.h>C89시각과 달력74장
<uchar.h>C11UTF-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

얼개를 폈으니 걷는다. 다음 두 장은 가장 많이 쓰고 가장 많이 미끄러지는 구역 — 스트림 입출력이다.