Proven C Book←↑→

머리말

이 책은 C 언어 입문서이자, 내가 만든 C 라이브러리 proven의 입문서이다. 이렇게 두 가지를 겸하게 된 데에는 이유가 있다.

무엇을 쓰라고 권하려면 먼저 그것이 왜 필요한지를 보여야 한다. proven이 다루는 문제들은 C의 미묘한 자리에 있다 — 표현의 한계, 변환의 규칙, 기억의 수명, 표준이 약속하지 않은 영역들. 이 자리들을 모르는 사람들에게 proven은 불필요한 물건으로 보인다. 한편 이미 잘 알고 있는 사람들에게는 그 문제들을 다루는 자신만의 방법이 있어서, 굳이 proven을 쓸 이유가 많지 않다.

그래서 라이브러리를 소개하기 전에, 그 문제들을 먼저 설명하기로 했다. C를 처음 배우는 사람을 염두에 두었기에, 이 책은 컴퓨터가 어떻게 생겼는지에서 시작해 자료형과 흐름, 포인터와 배열, 기억의 수명, 표준 라이브러리를 차례로 지나간다. 앞부분을 읽고 나서 proven이 필요 없다고 판단하더라도, 그것 또한 좋은 결말이다. 어느 쪽이든 C를 더 잘 이해하고 더 안전하게 쓰는 데에는 도움이 될 테니까.

사실 라이브러리와 입문서는 출발점도 목적도 같다. C를 쓰는 방식과 관습을 시대의 흐름에 맞게 한 단계 끌어올리는 것이다. 입문서는 그 바탕이 될 지식을 주고, 라이브러리는 새로운 코딩 관습을 제시한다. 같은 목표를 서로 다른 길로 이루려 할 뿐이다.

오래 살아온 C 언어에는 각 시대의 현실적인 한계와 어려움을 극복하려는 과정에서 생긴 다양한 상처와 뒤틀림, 그리고 진지한 고민의 흔적이 남아 있다. 그것들을 어루만지며 따라가 보는 일은 무척이나 흥미롭고 즐거운 경험이었으니, 거기에 내 나름의 노력을 보태 보고 싶어진 것은 당연한 흐름이리라. 목적은 앞에서 말한 대로지만, proven을 만든 것도 이 책을 쓴 것도 결국은 필요보다 C를 좋아하는 마음이 시킨 일이었음을 부정하지는 않겠다. 그 마음이 넘쳐 설명의 범위와 분량이 다소 과해진 데 대해서는 독자들에게 미리 양해를 구한다. 1,000쪽이 넘는 두께(앞으로도 늘어날 것이다)가 그 증거이고, 다음 절에서 말할 이 책의 한계도 절반은 거기서 온다.

이 책을 읽는 이들에게 감사의 뜻을 표하고자 한다. 누군가가 시간을 들여 내 글을 읽고 의견을 보태 준다는 것은 언제나 기쁜 일이다.

이 책의 의도와 이용 방법#

먼저 분명히 해 둘 것이 있다. 읽기만 해서는 프로그래밍 능력이 자라지 않는다. 이 책은 연습문제도, 과제도, “직접 해 보라”도 두지 않는다. 단지 상황을 설명하고, 질문을 던지고, 그에 대해 답을 제공할 뿐이다. 의도한 것은 독자에게 C 언어의 든든한 기초 지식을 갖추게 하고, 그 안에 내재된 함정과 위험을 알아보는 감각과 안목을 길러 주는 것이었다. 이것은 빈 파일 앞에서 문제를 잘게 쪼개고, 떠오르지 않는 함수 이름을 찾아내고, 컴파일러가 쏟아 낸 오류를 하나씩 지우고, 예상과 다른 출력 앞에서 원인을 좁혀 가는, 실제로 코드를 만들어 내는 능력과는 다소 다르다. 그것은 직접 써 보는 일로만 자란다. 이 책은 그 일을 대신 하지 않으며, 대신 할 수 있다고 말하지도 않겠다. 그 부분은 다른 실습 과정이나 자신의 작은 프로그램으로 이어 가야 한다.

그것은 이 책의 결함이지만 의도적 선택이기도 하다. 무엇보다 자리가 없었다. 설명만으로 이미 1,000쪽이 넘었으니 — 머리말에서 분량을 두고 미리 양해를 구한 그대로다 — 여기에 연습과 과제까지 실었다면 책은 두 배가 되고 독자의 부담도 그만큼 커졌을 것이다. 나는 부담 없이 끝까지 읽히는 쪽을 택했고, 그 대가로 수행 훈련을 포기했다. 이 책은 이해를 위한 책이지, 무엇인가를 빨리 만들어 내기 위한 책은 아니다.

다만 그 훈련을 다른 데서 하더라도 이 책의 자리는 남는다고 생각한다. C 에는 안전장치가 거의 없기 때문이다. 다른 언어라면 잘못 짚은 생각을 컴파일러나 실행기가 그 자리에서 막아 주지만, C 는 대개 그냥 받아들이고 그럴듯한 답을 내놓는다 — 어긋난 이해가 틀렸다는 신호 없이 살아남는다는 뜻이다. 그래서 기초가 얕은 채로 손부터 움직이면 훈련의 값이 비싸진다. 같은 것을 배우는 데 더 많은 시간과 시행착오가 들고, 더 나쁘게는 그 사이에 오개념이 굳는다. 굳은 오개념은 나중에 버그가 되고, 더러는 보안 취약점이 된다. 든든한 기초는 그 훈련을 대신하지는 못해도, 훨씬 싸게 만들어 준다.

첫 프로그램이 늦다는 것도 미리 말해 둔다. 헬로 월드는 제3부에서야 나온다. 그전까지는 컴퓨터가 어떻게 생겼는지, 기억이 어떻게 나뉘는지, 수와 글자가 어떻게 표현되는지와 같은 기초를 세운다. 늦은 데에는 그만한 이유가 있다. 제1부와 제2부는 곁들인 배경 설명이 아니라 그만한 무게를 지닌 자리이고, 나는 이 책에서 가장 값진 부분이 거기라고 생각한다. C 라는 언어의 생김새는 대부분 그 두 부에서 다룬 사정 — 기계가 기억을 다루는 방식, 표현할 수 있는 것과 없는 것, 번역이라는 과정 — 에서 비롯되었기 때문이다. 그러니 시간이 넉넉하지 않은 독자에게는 이렇게 권하고 싶다. 다른 곳을 다 건너뛰더라도 제1부와 제2부만은 읽어 두시라. 그리고 그 둘을 읽고 나면, 뒤에서 마주칠 물음들 — 정수는 왜 감아 도는가, 문자열의 끝은 왜 눈에 보이지 않는가, 컴파일러는 어째서 내가 쓴 대로 하지 않는가 — 가운데 적지 않은 것이 따로 배우지 않아도 저절로 풀릴 것이다. 물론 빨리 무언가를 만들고 싶은 독자에게는 이 순서가 답답할 수 있다. 그런 독자는 16장 헬로 월드를 먼저 읽고 1장으로 돌아와도 좋다. 이 책이 쓰여진 기준은 순서대로 읽는 것이지만, 읽는 사람의 수준과 용도에 따라 취사선택하면 된다. 고르는 데 도움이 되도록 수준별 단축 경로를 바로 다음 자리에 적어 두었다.

이 책이 의도한 것은 단단한 기반이다. 빠른 결과가 아니라 오래 가는 이해다. 다른 책과 강좌에서 익힌 기술은 이 기반 위에 놓일 때 훨씬 덜 흔들린다. 정수가 왜 감아 돌고, 포인터가 왜 그냥 숫자가 아니며, 컴파일러가 무엇을 약속하고 무엇을 약속하지 않는지를 알고 쓰는 사람과 모르고 쓰는 사람의 차이는 시간이 갈수록 벌어진다.

이 책에 실린 모든 코드는 실제로 컴파일되고 실행된 것이다. 인쇄된 실행 결과는 사람이 옮겨 적은 것이 아니라 책을 만들 때마다 기계가 예제를 돌려 얻은 출력이다. 기준은 gcc 이고 전부가 그것으로 통과하며, clang 으로도 교차 검증한다 — 다만 일곱은 건너뛴다. 넷은 예제가 일부러 일으키는 상황을 clang 이 정확히 진단해서이고(경고를 잠재우려 예제를 고치면 가르침이 무뎌진다), 셋은 그 도구모음에 없는 것 때문이다(GCC 전용 스위치, ASan 런타임). 무엇을 왜 건너뛰는지는 저장소에 적어 두었다.

밝혀 둘 것이 하나 더 있다. 이 책은 AI를 보조 도구로 삼아 집필했다. 무엇을 어떤 순서로 다룰지, 어떤 원칙으로 서술할지, 무엇을 싣고 무엇을 뺄지는 전부 내가 정했고, 원고는 그 지시에 따라 쓰인 뒤 내 검토를 거쳤다. 기술적 서술은 표준 문서와 1차 자료로 확인했으며, 앞 문단에서 말한 대로 예제는 사람이 아니라 기계가 매번 실제로 돌려 검증한다 — AI가 썼든 사람이 썼든 돌지 않는 코드는 이 책에 실리지 않는다는 뜻이다.

그럼에도 오류는 남아 있을 것이다. 그것은 도구의 몫이 아니라 내 몫이다. 발견하면 알려 주시기 바란다.