상세 차례
장 아래 절까지 펼친 차례다. 찾는 자리를 바로 짚을 때 쓴다.
제목과 색인 표제어에서 찾는다 --- 본문 전체가 아니다
제1부 — 바탕: 기계와 기억
2.1컴퓨터를 세 부품으로 그리기2.2비트 — 정보의 최소 단위2.2.1그런데 수학은 3을 가리킨다2.2.2실제로 만들어진 3진 컴퓨터 — Setun2.2.3그러면 왜 2진법이 이겼는가2.3그 단순한 기계의 시절, C가 태어났다
5.1네 구역, 하나의 비유5.2정적 구역이 둘로 나뉘는 이유 — bss라는 이상한 이름5.3세 구역의 성격 대조5.4이 밑그림이 통하는 데까지5.4.1표준에는 「스택」이라는 낱말이 없다5.4.2실제로 다른 기계들 — 지금도 있다5.5이 밑그림이 앞으로 쓰이는 곳
제2부 — 기계의 진짜 모습: 표현과 실행
6.1부호 없는 정수 — 시계처럼 도는 수6.2음수를 담는 세 가지 약속6.3세 약속의 경쟁, 그리고 C23의 결단6.4시프트 — 비트를 통째로 밀기6.5부호 확장(sign extension) — 좁은 그릇에서 넓은 그릇으로6.6눈으로 확인하기
7.1고정소수점 — 소수점을 약속으로 못박다7.2부동소수점 — 소수점을 데이터에 싣다7.3비트가 실제로 어떻게 나뉘는가7.4근사가 일으키는 세 가지 사건7.5난립, 그리고 IEEE 754라는 계약7.6눈으로 확인하기
8.1문자는 번호다8.2ASCII와 EBCDIC — 두 개의 표8.2.1「알파벳이 연속이 아니다」가 코드에 하는 일8.2.2그래서 라이브러리가 있다 — 추상이 하는 일8.3ISO 646 — 국가 변형과 C의 삼중자8.48비트의 백가쟁명, 그리고 한글8.5유니코드와 UTF-8 — 하나의 표, 영리한 담기8.6C가 가르는 두 문자 집합 — 소스와 실행8.6.1언제 옮겨 실리는가 — 번역 단계 1과 58.6.2C23 이 붙인 더 정확한 이름 — 리터럴 인코딩8.6.3인코딩을 못박는 접두어8.7같은 글자, 여러 표현 — 텍스트에 잠복한 보안 지형8.8글자들의 열 — 문자열을 담는 방식들
9.1펀치카드 — 한 장이 한 줄이다9.2라인프린터 — 줄 단위로 찍는 출력9.3프린터 터미널 — 종이 위의 대화, 그리고 tty9.4화면 터미널, 그리고 스트림이라는 유산9.5띠의 중간에는 통이 있다 — 버퍼9.6띠를 갈아 끼우다 — 리다이렉션과 파이프라인
11.1한 코어로 여럿을 — 번갈아 하기라는 발상11.2언제 끊을 것인가 — 세 가지 후보11.2.1스스로 내놓는 것만으로는 왜 부족한가11.3멀티태스킹의 갈래11.4전환할 때 무엇을 옮기는가 — 문맥11.5그 시점을 누가 알리는가 — 시계 인터럽트11.6장치와 잇는 선 — 줄지어 보내기와 한꺼번에 보내기11.7바깥이 말을 걸어오는 시점11.7.1인터럽트가 여럿이면11.7.2「물어본다」는 것이 무슨 뜻인가11.7.3처리하는 도중에 또 오면 — 기존 코드는 이렇게 견딘다11.8둘은 어떻게 다른가 — 인터럽트와 멀티태스킹11.9한때는 이것이 개인용 컴퓨터의 거의 전부였다11.10오늘 이 이야기가 어디로 이어지는가
12.1고백 — 그 그림은 과하게 단순했다12.2레지스터 — 원래부터 있던, CPU의 손안12.3벌어지는 격차 — 레지스터와 메모리 사이12.4캐시 — 격차의 틈에 끼어든 중간층12.5캐시의 분화 — 다층의 사다리12.6재어 보기 — 같은 개수, 다른 순서12.7또 하나의 사다리 — 가상기억12.7.1세그먼트에서 페이징으로12.7.2TLB — 번역에도 캐시가 붙는다12.7.3쪽 부재, 그리고 게으른 기억12.7.4보호 — 왜 널 참조는 대개 즉시 죽는가
13.1파이프라인 — 조립 라인 위의 명령들13.2분기 예측 — 갈림길을 미리 짐작하다13.3재어 보기 — 맞히기 쉬운 조건과 어려운 조건13.4클록의 한계, 그리고 멀티코어13.5같은 시대, C는 계약서를 썼다 — 표준 이전의 C와 C8913.6계약서에 없는 자리 — 회색지대13.7C 밖의 표준이 대신 보장할 때
14.1편집자의 작업실 — 컴파일러가 하는 일14.2추상 기계 — 계약서 속의 가상 기계14.3눈에 보이는 편집 — 값을 언제 읽고 언제 쓰는가14.4계약의 정밀화 — C99, C1114.5잘못된 신호 — 엄격한 앨리어싱 위반이 부르는 유령
제3부 — 첫 프로그램
16.1첫 프로그램16.2터미널과 셸 — 프로그램을 실행하는 자리16.2.1어떤 창과 어떤 일꾼이 있는가16.2.2셸이 하는 일 — 읽고, 가르고, 실행한다16.2.3내가 만든 실행 파일을 실행하기16.2.4인자 넘기기 — 프로그램에 값을 쥐여 주는 법16.3명령행에서 컴파일하고 실행하기16.3.1GCC (리눅스·macOS·MinGW)16.3.2Clang (macOS 기본, 리눅스·윈도)16.3.3MSVC (윈도)16.4그래서 첫 프로그램은 이렇게 나온다16.5한 줄씩 읽기16.6그런데, 소스에서 실행까지는 무슨 일이 있었나
17.1겉보기 — 명령 한 줄17.21주자 — 전처리: 텍스트를 짜깁기한다17.32주자 — 컴파일: C를 어셈블리로17.42주자의 안쪽 — 렉서와 파서17.53주자 — 어셈블: 기계 명령으로 찍어 내다17.64주자 — 링크: 조각을 잇고 구멍을 메운다
18.1필요한 것은 셋뿐이다18.2설치가 부담이면 — 웹에서 바로 해 보기18.2.1학습용 옵션 — 웹에서도 그대로18.3경고 — 공짜 검토를 켜 두어라18.4한글이 깨질 때 — 인코딩의 사슬18.4.1②와 ③을 컴파일러에 못박는 법18.5디버거 — 멈춰 세워 들여다보기18.6디버그 빌드의 옵션 — -g와 -O0은 다른 스위치다18.7디버거의 맹점 — 최적화된 빌드18.8디버그에선 되는데 릴리스에서만 틀린다18.9디버거를 믿기 어려울 때의 도구들18.10새니타이저 — 실행 중에 치는 그물18.11여기까지 온 자리
19.1세상의 큰 셋 — GCC, Clang/LLVM, MSVC19.2성능을 파는 컴파일러들 — 벤더 컴파일러19.3임베디드 — 다음 장의 입구19.4곁다리 하나 — 윈도우의 단정한 대안, Pelles C19.4.1윈도 앱을 C로 짠다는 선택19.4.2한 묶음에 들어 있는 것 — 자원 편집기와 대화 상자 디자이너19.5그 밖에, 그리고 은퇴한 이름들19.6공식 자료가 있는 곳
제4부 — 최소한의 도구 상자
21.1리터럴 — 소스에 적는 값21.2상수를 적는 법 — 한눈에 보기21.3정수 상수 (§6.4.4.1)21.4C23 의 자리 구분자 '21.5문자 상수 (§6.4.4.5)21.6부동소수점 상수 (§6.4.4.3)21.7문자열 리터럴 (§6.4.5)21.8상수처럼 보이는 것들21.9constexpr — C23 이 들여온 진짜 상수21.9.1무엇을 적는 것인가21.9.2const 와 무엇이 다른가21.9.3값이 정확히 담겨야 한다21.9.4파일 스코프에 두면 어떻게 되는가21.10수식 — 계산되어 값이 되는 것21.11순서 — 우선순위, 그리고 괄호라는 관행21.12미리 심는 주의 하나 — 계산의 시간 순서는 다를 수 있다
23.1printf — 서식이 있는 출력23.2빈칸의 종류 — 값마다 다른 자리23.3자리를 맞추는 법 — 폭과 정밀도23.4출력의 창구는 하나가 아니다23.5짝 맞추기 — 서식과 재료의 계약23.6제4부를 닫으며 — 헬로 월드 재독
제5부 — 선언: 이름을 만드는 법
25.1정의 — 일꾼을 만드는 문법25.2선언 — 계약 서명만 미리25.3선언에 붙는 낱말 하나 — inline25.3.1inline 은 명령이 아니라 부탁이다25.3.2주소를 얻을 수 있다 — 그리고 그 순간 실물이 필요해진다25.3.3C 의 inline 모형 — 규칙 한 줄과 그 파장25.3.4그래서 실무에서는 두 형태만 쓴다25.3.5인라인 정의에 붙는 두 가지 제한25.4스코프 — 이름이 보이는 범위25.5외상 청산 — int main(void)
26.1두 단계 — 읽고, 해석한다26.2fgets의 계약 — 무엇을 주고, 무엇은 말해 주지 않는가26.2.1잘렸는지는 어떻게 아는가26.3통에 무엇이 남는가 — 예상하고, 가져가고, 남긴다26.4해석은 실패할 수 있다26.5제5부를 닫으며
제6부 — 값과 흐름
27.1타입이 정하는 네 가지27.2첫 갈래 — 객체 타입과 함수 타입27.2.1완전 타입과 불완전 타입27.3기본 타입27.3.1문자 타입은 셋이다27.4정수·실수·산술 — 겹쳐 부르는 이름들27.5파생 타입 — 있는 것에서 만들어 내는 것27.6한정자 — 같은 타입의 한정판27.6.1한정판은 원본과 같은 크기다27.6.2순서는 자유롭고, 겹쳐 쓸 수 있다27.6.3_Atomic 만 얼굴이 둘이다27.6.4한정자는 값이 아니라 통로의 성질이다27.6.5붙일 수는 있어도 몰래 뗄 수는 없다27.6.6어디에 붙는지가 뜻을 뒤집는다27.7폭을 이름에 적는 타입들 — <stdint.h>27.7.1세 갈래를 가르는 기준은 「무엇을 요구하는가」다27.7.2uint8_t 의 함정 셋27.7.3그래서 무엇을 쓰는가27.8요약 — 표준의 낱말과 이 책의 장
28.1정수 타입 가족28.2기본 자료형 한눈에 보기 — 최소 범위와 실제 범위28.3정수 상수의 타입 — 같은 값도 표기에 따라 다르다28.4크기가 계약인 자리 — 고정 폭 타입28.5경계를 눈으로 본다
33.1루프 3형제33.1.1do-while 이 정말로 이기는 자리 — 거꾸로 세기33.2불변식(invariant) — 루프를 믿는 방법33.2.1세 조각으로 읽는다33.2.2사람들은 이 낱말을 어떻게 쓰는가33.2.3이진 탐색 — 불변식이 빛을 발하는 자리33.2.4무엇을 얻는가33.3for 의 첫 칸 — 무엇을 선언할 수 있는가33.3.1첫 칸의 이름은 어디까지 보이고 언제까지 사는가33.4조건 칸은 검사가 아니라 코드다33.5끝나지 않는 루프33.6겹쳐 도는 루프 — 이중, 삼중33.7재회 — Duff’s device
34.1값 복사 — 원본은 안전하다34.2“값 호출”과 “참조 호출” — 용어를 못박는다34.3부수효과와 평가 순서 — 씨앗의 회수34.4재귀 — 자신을 부르는 함수34.5마지막 연산자, 그리고 계약이라는 씨앗34.6연산자 한눈에 — 지금까지 만난 것들
35.1대입은 문장이 아니라 수식이다35.2대입이 하는 일은 셋이다35.3좌변도 평가된다35.4복합 대입 — 왼쪽을 한 번만 평가한다35.5어디서부터 계약 밖인가35.6대입에 숨는 변환
제7부 — 기억
36.1세 가지 표기 — 선언, &, *36.2sizeof — 그릇의 크기를 묻다36.2.1sizeof 가 내놓는 타입 — size_t36.3주소는 어떤 수인가 — 이름·크기·순서36.3.1왜 하필 정수였나36.3.2추상화는 시간이 갈수록 두꺼워졌다36.4주소를 인쇄하는 법36.4.1%p 의 정확한 계약36.4.2문자열로 만들어야 할 때 — uintptr_t와 PRIxPTR36.4.3그런데 — 주소를 정말 찍어야 하는가36.5포인터의 크기는 하나가 아니다
37.1nullptr — 비어 있음의 이름37.2어디까지 0을 써도 되는가 — 널 포인터 상수의 정확한 정의37.2.1담긴 뒤의 비트는 별개다37.3함정 — 표현을 0으로 가정하는 코드
38.1정렬과 캐스트 — char*의 특권38.1.1두 특권을 나란히 놓으면38.2프로버넌스 — 번호가 같아도 출처가 다르면38.2.1표준에 아직 없는 낱말38.2.2빈틈은 어디에 있었나 — 이웃한 두 변수38.2.3낱말이 태어난 자리 — DR26038.2.4명문화 — 설문 조사에서 기술 명세까지38.2.5들어오면 무엇이 달라지는가38.2.6출처를 하드웨어가 들고 다니는 기계
39.1선언, 접근, 순회39.2배열과 포인터 — 무너짐의 진실39.3원소와 원소 사이에는 빈자리가 없다39.4포인터의 덧셈은 보통의 덧셈이 아니다39.4.1주소를 정수로 담는 세 타입 — ptrdiff_t·intptr_t·uintptr_t39.4.2어디까지 허용되는가 — 산술의 계약39.5매개변수의 배열은 배열이 아니다39.6크기가 실행 중에 정해지는 배열 — VLA39.7매개변수의 [static N] — “최소 이만큼은 온다”39.7.1[static 1] — “널이 아니다”를 문법으로 적는 법39.7.2같은 대괄호 안의 한정자 — 그것은 포인터의 한정자다39.8경계 — 생사의 규칙
40.1배열의 배열 — 실체부터40.2첨자식이 풀리는 과정40.3매개변수 — 왜 int *가 아닌가40.4같은 주소, 다른 눈 — 평탄화의 계약40.5실무의 패턴들40.5.1평탄 + 선행 차원 — 수치 라이브러리의 공용어40.5.2행 포인터 배열 — 흩어진 행을 하나로 묶기40.6순회 순서와 캐시 — 왜 같은 계산이 몇 배씩 갈리는가
41.1왜 이 장이 따로 필요한가41.1.1왜 이 오해는 이렇게 질긴가41.1.2그리고 발각은 늦게 온다41.2무엇이 다른가 — 다섯 축41.3접근의 걸음 수 — 이것이 진짜 차이다41.4파일을 건너뛰는 사고41.5언제 같아지는가 — 세 규칙41.6무너지지 않는 자리41.76[a]가 합법인 이유41.8매개변수 변환은 한 겹만 일어난다41.9실무의 세 패턴 — 눈으로 보기41.9.1① 포인터의 배열 — 길이가 제각각인 것들을 묶는다41.9.2② 포인터의 포인터 — 남의 포인터를 고치는 자리41.9.3③ 자료를 옮기지 않고 순서만 바꾸기41.10그래서 C가 못 하는 것 — 그리고 반쯤 풀린 이야기41.10.1C99가 바꾼 것41.11골라 쓰기 — 실무의 판단
42.1중첩 루프 — 다차원을 걷는 법42.2다중 루프에서 빠져나오기42.3goto 가 정당한 두 자리42.3.1자리 ① — 여러 겹의 루프를 한 번에 벗기42.3.2자리 ② — 오류 처리의 정리 지점 모으기42.4매크로를 한 문장으로 — do { } while (0)42.5그 밖의 관용구와 함정42.5.1역순 순회 — size_t 로는 i >= 0 을 쓸 수 없다42.5.2나머지 관용구
43.1정체 — 배열, 그리고 약속43.2문자열 리터럴 — 읽기 전용의 땅43.2.1타입은 const가 아니다 — C의 이상한 자리43.3리터럴도 배열이다43.4이어 붙이기 — 인접한 리터럴은 하나가 된다43.5접두사 — 어떤 인코딩의 리터럴인가
44.1사고의 해부 — 경계 침범이라는 유행병44.2표준 도구들은 실패를 어떻게 알리는가44.3입력 해석의 실패를 다루는 다섯 규율44.3.1① 실패를 값으로 돌려준다44.3.2② 확인을 잊으면 컴파일러가 말하게 한다44.3.3③ 어디까지 읽었는지 알려준다44.3.4④ 잘림을 성공으로 치지 않는다44.3.5⑤ 실패하면 출력 인자를 건드리지 않는다44.4이 규율을 부품으로 굳히면
45.1표준의 네 축 — 저장 기간, 유효범위, 연결, 저장 클래스45.1.1저장 기간 — 넷45.1.2유효범위 — 넷45.1.3연결 — 셋45.1.4저장 클래스 지정자 일곱 — 한자리에 모아 놓고45.1.5이 자리는 하나뿐이다 — 그리고 그 예외45.2두 가지 수명45.3기억의 배치 — 구역들을 눈으로45.4스택 — 호출의 장부
46.1빌리고, 돌려준다46.2malloc을 어떻게 적을 것인가 — 오래된 논쟁46.2.1①이 권장되는 이유 넷46.2.2②를 권하는 쪽의 근거 — CERT MEM02-C46.2.3③과 「C++ 호환」이라는 이유 — 정말 그런가46.3돌려받은 주소의 정렬 — 무엇을 담을지 모르므로46.4값싸 보이는 두 줄의 값 — 할당은 왜 비싼가46.51차원으로 빌려 2차원으로 쓰기46.6소유 — 누가 돌려줄 책임을 지는가46.7제7부를 닫으며
제8부 — 자료의 모양
47.1선언, 초기화, 접근47.2sizeof의 첫 놀라움 — 멤버 크기의 합이 아니다47.3통째로 0으로 — { 0 }과 { }47.3.1무엇이 보장되는가47.3.2{0}과 {}의 미세한 차이 — 패딩47.4구조체는 값이다47.4.1대입은 되는데 비교는 안 되는 이유47.5머리와 데이터를 한 덩어리로 — 유연 배열 멤버47.5.1sizeof와 offsetof — 어느 것으로 크기를 셈하는가47.5.2그래서 대입은 되는가 — 유연 배열 멤버와 복사
48.1중첩과 접근 — 점과 화살표를 섞어 읽기48.2임시 구조체 — 복합 리터럴48.3이름 붙은 인자 — 구조체 하나로 넘기기48.4패딩 — 멤버 사이의 빈자리48.4.1꼬리 패딩은 왜 있는가 — 답은 「구조체의 배열」에 있다48.4.2구조체의 배열과 포인터 — 실무의 패턴48.5통째로 저장하거나 보내면 안 되는 이유48.5.1그래서 어떻게 하는가 — 필드별 직렬화48.6패딩을 없애는 법, 정렬을 강제하는 법48.6.1alignas — 다섯째 갈래, 정렬 지정자48.7이름 없는 멤버와 container_of48.7.1익명 구조체·공용체 (C11)48.7.2container_of — 멤버에서 바깥을 되찾기48.8배열을 값으로 넘기기 — 되는가, 그리고 해야 하는가
49.1공용체 — 겹쳐 놓기49.2표현을 눈으로 — 엔디안과 패딩49.3활성 멤버와 타입 펀닝 — 같은 비트를 다른 눈으로49.3.1값이 아닌 비트열 — 비값 표현49.3.2공용체의 크기와 정렬, 그리고 공통 초기 시퀀스49.4비트 필드 — 한 워드를 쪼개 쓰기49.4.1비트 필드에서 구현이 정하는 것들49.5구조체와 공용체를 섞는 실무 패턴49.5.1실물 하나 — 2바이트 조합형 한글49.6제8부를 닫으며
제9부 — 깊은 구석들
50.1수식이 가진 네 가지50.2우선순위와 결합50.3자주 미끄러지는 자리들50.4전위와 후위 — 같은 일을 하고 다른 값을 준다50.4.1표준이 정한 계약50.4.2값이 정해지는 때와 메모리가 바뀌는 때50.4.3「전위가 빠르다」는 이야기의 진실50.4.4C++ 에서는 두 가지가 달라진다50.5연산자별 계약50.6후위 연산자50.7단항 연산자50.8산술 연산자50.9시프트 연산자50.10관계·상등 연산자50.11비트·논리 연산자50.12조건·대입·쉼표50.13평가 순서와 시퀀스 포인트50.14회색지대 총람50.14.1정의되지 않은 동작(UB)50.14.2미지정(unspecified)50.14.3구현 정의(implementation-defined)50.15연산자가 아닌 것들
51.1다섯 가지 기본 동작51.1.1마스크 만들기, 그리고 벼랑51.2플래그 집합 — 가장 흔한 쓰임51.3관용구 — 그리고 왜 그렇게 되는가51.4C23 — 관용구가 이름을 얻다51.5원칙 일곱51.6여기서 잘 나는 사고들51.7손으로 최적화하기 전에51.8실물 — 비트는 어디에 쓰이는가51.9되짚기
54.1세 가지 회색지대 — UB, 미지정, 구현 정의54.2왜 존재하는가54.3“무엇이든 가능함”의 실제 얼굴54.4계산이 시작되기도 전에 — 파일 모양의 UB54.5그 밖의 기묘한 UB들54.6일부러 만드는 UB — unreachable54.7피하는 법 — 규율, 도구, 그리고 부품54.8제9부를 닫으며
제10부 — 구성
57.1링크는 한 단계가 아니다 — 세 이름57.2동적 링크의 진짜 목적 — 크기가 아니라 ABI57.3ABI 가 약속하는 것 — 조목조목57.4무엇이 ABI 를 깨뜨리는가57.5깨뜨리지 않고 고치는 법57.6위치 독립 코드(PIC) — 왜 라이브러리는 이렇게 지어야 하는가57.7이름이 겹치면 갈아치워진다 — interpositioning
58.1스코프란 무엇인가 — 「보이는 곳」이 아니라 「그 이름이 그것을 뜻하는 곳」58.2네 가지 스코프58.3스코프는 어디서 시작하는가 — 등호 앞이다58.4가림 — 안쪽이 바깥쪽을 덮는다58.5전처리기는 스코프를 모른다58.6스코프·수명·연결 — 자주 뒤섞이는 셋
59.1「C에는 이름 공간이 없다」는 말의 진실59.2네 이름 공간59.3세 축 — 스코프·연결·이름 공간59.4태그가 따로 사는 덕분에 생긴 관행59.4.1typedef struct node node;59.4.2그런데 typedef를 쓰지 말라는 규약도 있다59.5열거 상수는 보통 식별자다59.6가림(shadowing)59.7써서는 안 되는 이름 — 예약된 마당
60.1충돌은 언제 어디서 터지는가60.2첫째 무기 — 내보내지 않기(static)60.3둘째 무기 — 접두어 규약60.4셋째 무기 — 심볼 가시성60.5넷째 무기 — 이름 자체를 줄이기60.6C++ 는 이 자리를 어떻게 풀었는가60.6.1문법60.6.2익명 이름 공간 — C의 static에 해당60.6.3using namespace — 편의와 그 대가60.6.4ADL — 인자를 보고 마당을 찾는다60.6.5이름 맹글링과 extern "C"60.7좋은 습관 — 요약
61.1매크로 — 이름을 토큰 열로 바꾸기61.1.1괄호 — 매크로를 쓰는 사람이 가장 먼저 배우는 것61.2# — 토큰을 문자열로 (stringize)61.3## — 토큰 두 개를 하나로 (token paste)61.4두 겹 우회(double expansion) — 왜 한 겹으로는 안 풀리는가61.4.1먼저 이름부터 — 규칙 넷61.4.2손으로 따라가는 전개 — 두 줄의 대조61.4.3표준이 든 예 — glue와 xglue61.5표준이 든 기묘한 예들61.5.1① 자리표시자(placemarker) — 빈 인자를 붙이면61.5.2② 표준이 “미지정”이라고 못 박은 전개61.5.3③ __VA_OPT__ — “비었다”를 언제 판정하는가61.6X 매크로 — 목록 하나에서 코드 여러 벌을61.7번역 단계 — 표준이 못박은 여덟 걸음
62.1셋을 갈라 놓는다 — 선언, 정의, 호출식62.1.1호출식은 연산자다62.1.2C23 이 정리한 옛 자리62.2인자는 대입하듯 들어간다62.3순서 — 표준이 정하지 않은 것62.3.1순서가 있는 자리62.4한 번의 호출, 다섯 걸음62.5레지스터인가 스택인가 — 예산이 있다62.5.1치우는 쪽이 갈리면 이름도 갈린다62.6기묘한 사례들 — ARM 과 임베디드62.7구조체를 주고받을 때62.8함수 포인터를 돌려주는 함수62.9여기서 잘 나는 사고들62.10되짚기
63.1네 개의 도구63.2기본 인자 승격 — ...을 건너는 값은 굵어진다63.3근본적 한계 — 함수는 아무것도 모른다63.4_Generic — 타입을 컴파일 시간에 붙잡기63.5proven의 PROVEN_ARG — 실물의 구조63.6역사 — varargs에서 stdarg로
64.1이름은 포인터로 무너진다64.2타입이 곧 계약이다64.3void *와 함수 포인터는 다른 세계다64.4함수 포인터를 인쇄하는 법64.4.1왜 %p에 넘길 수 없는가64.4.2이식성 있는 길 — 바이트로 떠서 찍기64.4.3가장 좋은 답 — 주소 대신 이름64.5디스패치 표 — switch 대신 배열64.6가상 함수 표 — C로 짓는 객체지향
65.1두 가지 독법65.2독법 ① 실습 — 영어 어순으로 이어 읽기65.2.1이 읽기에는 이름이 있다 — 우경식(boustrophedon)65.2.2지워 가며 읽기65.3독법 ② — 이름이 없을 때65.4typedef — 층을 나누어 이름을 붙인다65.4.1어디에 쓰고 어디에 쓰지 않을 것인가65.5실물 — 실무에서 실제로 쓰인 선언들65.5.1① 표준이 직접 낳은 괴물 — signal65.5.2② 실제로 더 험한 것 — X11의 오류 처리기65.5.3③ 그리고 정말로 무의미한 것65.6도구에 맡기기 — cdecl
제11부 — 표준 라이브러리 정독
68.1열고, 쓰고, 닫기 — 실패는 세 번 일어날 수 있다68.2파일 끝을 아는 법 — feof의 오용68.3버퍼 크기보다 긴 줄68.4텍스트 모드와 이진 모드68.5파일 위치와 크기
70.1strncpy의 진실70.2그러면 무엇을 쓰는가70.3겹치는 영역 — memcpy와 memmove70.4strtok — 원본을 부수고 상태를 숨긴다70.5나머지 함수들의 함정
71.1변환 — atoi를 버리는 이유71.2동적 할당 — 네 함수와 그 계약71.3종료 — 네 가지 방법의 차이71.4정렬과 탐색 — qsort·bsearch71.5난수 — rand의 한계71.6환경과 프로세스
72.1함수 열두 개를 한눈에72.2첫 번째 함정 — char를 그대로 넘기지 않는다72.3두 번째 함정 — EOF가 섞여 들어온다72.4판정은 로케일에 달렸다72.5여러 바이트 문자에는 무의미하다
73.1왜 있는가 — 관습은 나라마다 다르다73.2로케일은 프로그램 전역 상태다73.3여섯 범주 — 무엇이 무엇을 지배하는가73.4setlocale의 정확한 계약73.5로케일 이름의 문법73.5.1문자집합 이름과 정규화73.5.2다른 세계의 이름 — BCP 47과 Windows73.6환경 변수의 우선순위73.7로케일 데이터는 어디에 있는가
74.1창구 하나 — localeconv74.1.1스물네 멤버를 한눈에74.1.2자리 묶음 문자열의 인코딩74.1.3통화 표기는 세 값으로 조립된다74.2LC_NUMERIC — 조용히 데이터를 망가뜨리는 자리74.3LC_TIME — 날짜와 시각의 표기74.4LC_COLLATE — strcmp는 사전순이 아니다74.4.1strxfrm — 왜 이런 함수가 있는가74.5스레드와 로케일74.6실무의 처방
75.1표준이 정한 것과 정하지 않은 것75.2다섯 가지 문자 상수와 문자열75.3MB_CUR_MAX와 MB_LEN_MAX75.4변환 함수의 세 층75.4.1mbstate_t가 왜 필요한가75.5mbrtowc — 한 단계씩 뜯어보기75.5.1문자열 통째로 — mbsrtowcs
76.1두 진영으로 갈린 wchar_t76.2UTF-16의 한계와 서러게이트 쌍76.3Windows — W 함수군과 그 정확한 인코딩76.4리눅스와 glibc — 크지만 쓰이지 않는다76.5툴킷의 선택 — GTK와 Qt76.6스트림에는 방향이 있다
77.1원칙 — UTF-8을 안에, 변환은 경계에만77.2검증 — 문법이 맞아도 거절해야 하는 것들77.3「글자 수」의 세 층위, 그리고 넷째77.4정규화 — 같은 글자, 다른 바이트77.5대소문자와 정렬은 언어에 달렸다77.6아직 살아 있는 레거시 — 2바이트 인코딩77.7변환은 무엇으로 하는가
80.1errno — 전역으로 오류를 나르는 대가80.2assert — 계약을 코드로 적는 가장 싼 방법80.3신호 — 다음 장으로80.4비지역 점프(non-local jump) — setjmp/longjmp
81.1어디서 왔는가 — 유닉스의 유산81.2함수 두 개 — 정확한 모양81.2.1signal의 인자와 반환값81.2.2raise의 인자와 반환값81.2.3표준이 정한 신호 여섯 개81.3처리기 안에서 무엇을 할 수 있는가81.3.1sig_atomic_t의 정체81.4처리기와 기억 — 왜 malloc이 목록에 없는가81.5신호가 저장하고 되돌리는 것 — 레지스터 문맥과 errno81.5.1errno는 예외다 — 손으로 챙겨야 한다81.6실무의 패턴 — 깃발을 세우고 즉시 돌아간다81.7POSIX의 sigaction — 표준이 남긴 빈틈을 메운다81.7.1struct sigaction의 속81.7.2siginfo_t — 누가, 왜 보냈는가81.7.3신호를 잠시 막아 두기 — 마스크81.8실제 사용 사례81.8.1정상 종료 — 가장 널리 쓰이는 패턴81.8.2SIGPIPE — 무시하는 것이 정답인 신호81.8.3시스템 호출이 끊기는 문제 — EINTR81.8.4어떤 소프트웨어가, 왜 신호를 쓰는가
82.1왜 있는가 — 예외가 없는 언어의 궁여지책82.2두 낱말 — 정확한 모양82.2.1setjmp — 두 번 돌아오는 것처럼 보이는 매크로82.2.2setjmp를 쓸 수 있는 자리 — 네 가지뿐82.2.3longjmp — 뛰기 전에 확인할 세 가지82.3jmp_buf의 정체82.3.1여덟 칸을 들여다보면82.3.2이것이 곧 volatile 규칙이다82.4돌아왔을 때 값은 어떻게 되는가 — volatile 규칙82.5자원은 아무도 정리해 주지 않는다82.5.1더 조용한 사고 — 포인터가 옛 값으로 되돌아간다82.6실제로 무엇이 이것으로 지어졌는가82.6.1이들은 기억을 어떻게 감당하는가 — 답이 전부 같다82.7POSIX의 sigsetjmp/siglongjmp82.8오늘날의 자리 — 언제 쓰고, 무엇으로 대신하는가
84.1왜 표준에 스레드가 들어왔나84.2첫 갈래 — 만들고 기다리기84.3그런데 값이 어긋난다84.4상호 배제 — mtx_*84.5기다리기 — cnd_*84.6한 번만 — call_once84.7갈래마다 따로 — thread_local 과 tss_*84.8★ 그런데 왜 실무는 pthread 를 쓰는가84.9쓸 자리와 쓰지 않을 자리
85.1잃어버린 갱신 — 눈으로 확인한다85.2volatile은 왜 답이 아닌가85.3원자적 타입과 연산85.3.1CAS — 「그대로면 바꿔라」85.4메모리 순서 — 건드리지 않는 것이 기본85.4.1왜 「순서」가 문제가 되는가85.4.2짝이 벽을 세운다 — release 와 acquire85.4.3순서는 공짜인가 — 재어 본다85.5잠금 없음(lock-free)이라는 말85.6쓸 자리와 쓰지 않을 자리85.7자물쇠를 쥔 쪽이 멈추면 — 우선순위 역전과 스핀락85.7.1같은 병의 다른 얼굴 — 사용자 공간의 스핀락
87.1무엇이 승격됐나87.2bool — 무엇을 막는가87.3nullptr — 이름 바꾸기가 아니다87.4나머지 승격과 새 낱말87.5속성 — 타입이 담지 못하는 뜻을 적는다87.5.1속성은 무엇을 하는가 — 재어 본다87.5.2모르는 속성은 무시한다87.6기존 코드를 어떻게 옮기는가
88.1실행 파일 안의 구역, 주소 공간의 구역88.2리눅스의 배치88.3윈도우의 배치88.4운영체제가 없는 세계 — 자유 사용 구현88.4.1Arm Cortex-M — 벡터 테이블의 첫 워드가 스택이다88.4.2AVR — 하버드 구조라 상수도 복사한다88.4.3PIC — 뱅크와 “컴파일된 스택”
89.1장부 ① — 블록마다 붙는 머리말89.2장부 ② — 크기별 목록과 갈래별 캐시89.3단편화 — 누수가 없는데도 메모리가 는다89.4표준 malloc을 갈아 끼우기 — 대안 할당자들89.5크기를 돌려주는 해제 — C23 의 free_sized89.6대안 표준 라이브러리89.7모양을 바꾸는 대안 — 아레나, 풀, 그리고 할당자를 인자로
제12부 — proven — 새로운 안정적인 기반
90.1하나 — 문자열 함수는 그릇의 크기를 모른다90.2둘 — 실패를 확인하게 만드는 장치가 없다90.3셋 — printf는 우리가 말하는 것을 그대로 믿는다90.4넷 — 이건 누가 해제하나90.5다섯 — 아무도 타입을 검사해 줄 수 없는 콜백90.6여섯 번째 — 바이트에는 타입이 있다
91.1왜 이 라이브러리가 있는가91.2이름이 말하는 것 — 유래(provenance)91.3무엇을 대신하려는가91.4설계를 결정한 약속들91.5무엇이 아닌가91.6설치할 것이 없다는 선택91.7이 책의 예제는 어떻게 빌드되는가91.8첫 프로그램91.9세 가지 규칙 — 이 부 전체를 읽는 열쇠91.10객체 하나의 일생91.11내 프로젝트에 붙이기 — 최소 Makefile
92.1두 가지 반환 모양92.1.1에러 코드 전수92.1.2결과 꾸러미의 갈래92.2버리면 컴파일러가 항의한다92.3실패했을 때 남는 것 — 실패 원자성92.4실패를 위로 올리는 법 — 정리와 함께92.5돌려줄 상대가 없을 때 — 패닉
93.1바이트에는 이름이 있다93.2뷰 — 포인터와 길이를 하나로93.3자르기 — 이 부에서 가장 자주 쓰는 연산93.4넘치지 않는 크기 산술93.5정렬 — 다음 경계로 밀어 올리기
95.1두 개의 타입, 하나의 규칙95.2거부하되, 자르지 않는다95.3세 갈래의 쓰기 — 거부·자름·성장95.4문자열을 고치는 연산들95.5찾기와 자르기 — 복사 없는 텍스트 처리95.6두 세계의 경계 — NUL 종단과 UTF-16
97.1네 컨테이너의 한살이97.2자라는 배열97.3침습적 리스트 — 할당 없는 연결97.4링 버퍼 — 고정 크기의 흐름97.5해시 맵, 그리고 공격받는 자료구조97.6최악을 보장하는 정렬97.7바이트를 글자로 — 해시와 인코딩
98.1파일 하나의 한살이98.1.1한 번에 읽고 쓰는 편의 함수들98.2스트림 — 버퍼를 둔 읽고 쓰기98.3시간 — 두 가지 다른 시계98.4난수 — 용도가 물건을 정한다98.5메모리 매핑
99.1스택리스 코루틴 — 스레드 없이 겹쳐 돌리기99.2작업 시스템 — 코어를 여럿 쓰기99.3스레드, 할당자, 그리고 출처99.4OS 가 없을 때 — 프리스탠딩99.4.1실제 빌드 절차99.5이 라이브러리의 자리 — 무엇이고, 무엇이 아닌가99.5.1지금 무엇이 검증되었는가99.5.2안정성 — 지금은 무엇이 바뀔 수 있는가99.5.3아직 없는 것99.6언제 쓰지 않는 것이 나은가
100.1무엇을 만들 것인가100.2순수 C 판100.3proven 판100.4한 걸음 더 — 중첩과, 재귀 없는 구현100.4.1무엇을 어디에 썼는가100.5그래서 무엇이 달라졌는가
제13부 — 닫으며
101.1make — 무엇을 다시 만들 것인가101.2git — 무엇이 언제 바뀌었나101.3도구 상자의 나머지 — 빌드, 관측, 검사101.3.1① 무엇을 어떻게 만들 것인가 — 빌드와 의존성101.3.2② 무엇이 잘못됐는가 — 디버거와 기록·재생101.3.3③ 어디가 느린가 — 프로파일러101.3.4④ 코드가 옳은가 — 검사와 시험101.3.5⑤ 사람이 읽기 좋은가 — 서식과 문서101.4오늘도 C로 도는 것들 — 그리고 왜101.5업계의 규약 — MISRA C와 그 이웃들101.5.1MISRA C — 자동차에서 나와 업계 전체로101.5.2이웃들 — 안전 규격과 코딩 규칙101.5.3무엇을 금지하는가 — 공통된 패턴101.6C와 C++ — 형제이지, 부모와 자식이 아니다101.7C 코드를 C++ 컴파일러에 넣으면101.8C++ 쪽의 시간은 더 빨리 흐른다101.9섞어 쓰는 법 — extern "C"101.10임베디드 — C의 본진101.11한계를 넘는 법 — 실전의 요령
102.1빌드가 있으면 무엇이 달라지는가102.2파일을 어떻게 나누는가 — 헤더는 계약, 소스는 사정102.3공개와 내부의 경계102.4폴더 구조 — 관행은 무엇을 위한 것인가102.5시험의 갈래 — 각각 무엇을 잡는가102.6골든 시험 — 정답을 파일로 굳힌다102.7얼마나, 그리고 무엇을 시험하지 않는가102.8협업 — 기계가 막는 것과 사람이 보는 것102.9적어 두어야 하는 것
103.1이름이 없으면 같은 것을 다르게 부른다103.2픽스처 — 시험이 딛고 서는 판103.3증인 — 검사는 결함의 묘비다103.4음성 검사 — 그 검사가 정말 무는가103.5래칫 — 늘면 안 되는 수103.6티어 — 늘 전부 돌릴 수는 없다103.7한 건의 일 — 결정과 실행을 가른다103.8조용한 실패 금지 — 그리고 커밋은 결정의 기록이다
부록과 찾아보기
서식 지정의 뼈대출력 변환 — 전체 목록플래그, 폭, 정밀도길이 수식어 — 타입의 폭을 알려 주는 자리고정 폭 정수의 서식입력 변환 — 전체 목록입력에서만 통하는 규칙들반환값 정리자주 하는 실수 모음
정수 승격통상 산술 변환 (두 피연산자의 공통 타입)가변 인자의 기본 진급정수 변환 등급 (변환 규칙의 기준자)어떤 변환이 어떤 위험을 부르는가조용한 변환이 일어나는 자리 목록그 밖의 자주 만나는 변환
옌스 구스테트, 『모던 C』 — 표준을 기준으로 삼는 교재K. N. 킹, C Programming: A Modern Approach — 정통 교과서크리스토퍼 프레셰른, 『우아한 C언어 코딩 패턴』 — 설계와 패턴온라인 참고서브라우저에서 바로 돌려 보는 곳눈으로 보는 도구문제를 주는 곳무료로 읽을 수 있는 자료자료를 고르는 눈 — 오래된 것을 가려내기표준 문서를 구하는 법이 책 다음의 길
문법을 적는 표기 — BNF에서 EBNF로C 표준의 표기법 읽는 법A.1 어휘 문법A.1.1 어휘 요소A.1.2 키워드A.1.3 식별자A.1.4 보편 문자 이름A.1.5 상수A.1.6 문자열 리터럴A.1.7 구두점A.1.8 헤더 이름A.1.9 전처리 수A.2 구문 문법A.2.1 식A.2.2 선언A.2.3 문장A.2.4 외부 정의A.3 전처리 지시문문법이 답하지 못하는 것표준 문서에서 문법을 찾는 법
<string.h> — 문자열과 기억기억 블록 다루기 (mem*)복사와 이어 붙이기 (strcpy·strcat 계열)견주기와 길이찾기와 쪼개기오류 문자열<ctype.h> — 한 바이트의 갈래<stdckdint.h> — 넘침을 묻는 산술<assert.h> — 계약을 실행 중에 확인한다<errno.h> — 실패의 까닭을 남기는 자리<setjmp.h> — 되돌아갈 자리를 적어 둔다<stdarg.h> — 개수를 모르는 인자를 훑는다<stddef.h> — 이름 없는 것들에 이름을 준다<stdbool.h>·<stdalign.h> — 비어 버린 두 헤더<iso646.h>·<stdnoreturn.h> — 흉터 하나와 물러난 이름 하나<limits.h> — 정수가 담을 수 있는 끝<float.h> — 실수가 담을 수 있는 끝<stdint.h> — 폭을 못박은 정수<inttypes.h> — 그 정수를 찍고 읽는 법<stdbit.h> — 비트를 세는 표준 방법<locale.h> — 「어디의 관습인가」를 바꾼다<wctype.h> — 와이드 문자의 갈래<uchar.h> — 유니코드 폭을 못박은 문자<signal.h> — 밖에서 들어오는 끼어듦<fenv.h> — 부동소수점 환경을 만진다<tgmath.h> — 타입에 맞는 것을 골라 준다<complex.h> — 복소수<threads.h> — 표준이 정한 스레드<stdatomic.h> — 쪼개지지 않는 연산<wchar.h> — 와이드 문자의 모든 것<time.h> — 시각과 시간<stdlib.h> — 잡동사니 서랍<stdio.h> — 스트림 입출력<math.h> — 수학 함수
왜 그런가 — 표준 C 가 주지 않는 것그래도 표준 C 만으로 되는 것간극의 정체 — C 실력의 문제가 아니다갈래 넷 — 무엇을 더 배워야 하는가화면에 창 하나 — GUI 로 가는 길무엇을 만들 것인가어디서 배울 것인가C 를 더 파고들 곳컴퓨터 과학을 넓게 볼 곳길잡이와 목록
덤프란 무엇인가무엇이 들어 있고, 무엇이 없는가파일의 모양 — 리눅스의 코어는 ELF 다주소를 이름으로 바꾸기스택을 되감는 법읽는 절차덤프가 남게 만들기 — 그리고 안 남는 흔한 이유여기서 남기는 것
로더가 파일에게 묻는 네 가지머리가 없는 형식 — 도스의 .COMMZ — 도스가 붙인 최초의 머리a.out — 유닉스의 첫 형식, 그리고 그 한계COFF, 그리고 그 후손 PEELF — 두 개의 목록그 밖의 형식들, 그리고 매직 숫자여기서 남기는 것
이 부록을 여는 말전원이 들어오면 — OS 없이 도는 기계OS가 해 주던 일의 목록「초기화하지 않은 전역은 0」은 공짜가 아니다리셋 벡터(reset vector) — 기계가 처음 읽는 자리여기서 남기는 것인터럽트 — 흐름을 가로채는 장치세 낱말을 먼저 가른다이미 써 본 적이 있다 — 하드웨어 예외가 C 함수까지 오는 길인터럽트는 세지 않는다처리기를 C 로 쓸 수 있는가 — 칩마다 답이 다르다처리기 안에서 할 수 있는 일이 왜 그렇게 적은가여기서 남기는 것레지스터를 만지는 법 — 기억 사상 입출력과 volatile장치가 주소를 차지한다이름을 붙이자 — 기억 사상 입출력(memory-mapped I/O)반대편 — 명령으로 입출력을 밝히는 방식(port-mapped I/O)그래서 volatile 이 있다내 기억을 바꾸는 것이 인터럽트만은 아니다 — DMAvolatile 이 해 주지 않는 것인터럽트를 잠깐 끄는 것 — 가장 오래된 자물쇠비트 필드로 하드웨어 레지스터를 그리지 말 것여기서 남기는 것제약 속의 C, 그리고 되가져가기타이머 인터럽트 하나를 끝까지할당자 없이 사는 법폭을 이름에 적는다소수를 정수로 다루기 — 고정소수점스택은 얼마나 깊어지는가시간과 전력이 코드에 보인다되가져가기 — OS 위에서 다시 읽기
전원이 들어오면BIOS 시대 — 512바이트가 전부였다디스크의 배치도 — MBR 에서 GPT 로UEFI — 펌웨어가 파일 시스템을 읽는다부트로더가 실제로 하는 일왜 여러 단계인가 — 446바이트의 그늘UEFI 경로 — 이름과 변수로 찾는다부트로더 없이 — 리눅스 EFI 스텁임베디드 — U-Boot 와 MCUboot넘겨줄 때 무엇을 물려주는가안 뜰 때 — 증상으로 칸을 가린다운영체제마다 — 그 뒤에 무슨 일이 일어나는가MS-DOS윈도우리눅스RTOS 와 작은 기계사슬이 곧 신뢰의 사슬여기서 남기는 것
먼저 알아 둘 낱말연결을 가르는 네 축가장 오래된 선 — UART 와 RS-232프레임 — 놀고 있는 선에서 글자를 오려 내는 법RS-232 — 같은 프레임, 다른 전압흐름 제어 — 「잠깐만」이라고 말하는 법UART 가 알려 주는 오류 넷병렬은 왜 사라졌나두 선으로 여럿 — I2C네 선으로 빠르게 — SPI한 선으로도, 그리고 아무나 말해도 — 1-Wire 와 CAN기계 안의 큰길 — PCI 와 PCI Express설정 공간 — 장치가 자기를 소개하는 256바이트밖으로 나가는 큰길 — USB끼어들기 — IRQ대신 옮기기 — DMA셋을 견주면 — 폴링, 인터럽트, DMA여기서 남기는 것
먼저 알아 둘 낱말디스크는 번호 붙은 칸의 줄이다왜 나누는가MBR — 첫 섹터 512바이트에 다 적는다파티션 항목 16바이트파티션이 넷으로 모자랄 때 — 확장 파티션과 EBR 사슬GPT — 배열과 검사와 사본으로 다시 지었다보호 MBR — 0번 섹터는 여전히 MBR 이다GPT 헤더 92바이트GPT 파티션 항목 128바이트GUID 는 글로 쓸 때와 디스크에 놓일 때가 다르다정렬 — 왜 하필 2048섹터에서 시작하는가파티션 안에는 무엇이 있나 — 파일 시스템의 첫 섹터FAT32 — 가장 읽기 쉬운 예ext4 와 NTFS 는 어떻게 다른가매체의 물리 — 왜 무작위 쓰기가 느린가회전하는 원판 — 자리를 찾아가는 시간반도체 — 쓰는 단위와 지우는 단위가 다르다이 기계에서 잰 것fsync — 캐시로 감출 수 없는 값무엇이 어디서 깨지는가여기서 남기는 것
왜 재는가 — 개념만 알면 남는 것은 틀린 직관이다재는 도구를 먼저 잰다① 기계의 숫자를 예제가 스스로 읽는다② 해상도와 ③ 값은 다르다④ 첫 번째 함정 — 최적화가 재려던 것을 지운다⑤ 두 번째 함정 — 첫 회는 느리다⑥ 세 번째 함정 — 평균은 한 번의 방해에 끌려간다이 부록의 여섯 규율기억의 사다리를 재다먼저 원리 — 왜 사다리가 생겼는가그래서 어떻게 재야 하는가잰 것 — 계단이 보인다줄과 걸음 — 캐시가 실어 오는 단위먼저 원리 — 왜 낱개가 아니라 줄인가재는 방법 — 걸음 폭을 바꾸되 횟수는 고정잰 것 — 줄이 시간에 나타난다같은 자료, 다른 배치 — AoS 와 SoA번역에도 값이 있다 — TLB 와 쪽먼저 원리 — 번역표와 그 캐시재는 방법 — 자료는 조금, 쪽은 많이잰 것 셋갈림길의 값 — 분기 예측먼저 원리 — 왜 미리 짐작해야 하는가재기 전에 — 분기가 아직 남아 있는가잰 것얼마나 규칙적이어야 맞히는가코어 사이의 값 — 거짓 공유와 원자 연산먼저 원리 — 줄은 한 번에 한 코어의 것거짓 공유 — 남의 변수 때문에 내가 느려진다잰 것진짜로 함께 쓰는 값 — 원자 연산과 자물쇠수의 값 — 부동소수점먼저, 이 절의 측정이 한 번 실패했다잰 것 ① — 비정규수는 71배 느렸다잰 것 ② — float 가 double 보다 빠른가잰 것 ③ — 연산마다 값이 다르다잰 것을 한자리에ARM 실기에서 다시 재 보면이 수를 어떻게 쓰나여기서 남기는 것