C언어에 대해서 Programming/C 2017. 5. 22. 16:52


C언어가 개발된지도 어느덧 40여년이 넘는 시간이 지났다. 이 긴 시간 동안 많은 숫자의 언어들이 생겨나고 발전하였으며 그만큼 사라져갔다. 이 흐름 속에서 C언어는 다른 언어와는 차별화되는 자기만의 영역을 구축하였고 이를 통해 독보적인 위치에 있을 수 있었다. 하지만 90년도에 자바의 등장으로 엄청난 인기를 끌게되면서 C와 C++은 이제 한물 간 언어라는 위기론이 대두되었고 이는 현대에 와서도 지속적으로 이야기가 나오고 있다.

사실 완벽하게 부정하기는 힘든 논제이다. 기술의 발전으로 하드웨어의 사양이 눈이 부시게 발전하였고 프로그래밍 언어가 생겨나고 사라지면서 생긴 간편한 문법들은 더이상 진입장벽이 높은 C 를 사용할 필요성을 느끼지 못하게 하였다. 분야에 따라서는 C를 전혀 모른다고 해도 개발하는데 지장이 없을 정도이다. 하지만 그럼에도 불구하고 C언어는 특유의 LOW한 특징 때문에 여전히 매력적이다. 앞으로 계속해서 설명하겠지만 다른 언어들에 비해 C는 어떤 용도를 가지고 사용하더라도 제약 사항이 매우 적으며 자유도가 풍부하고 매우 간결하다. 이는 분명 현대에 와서도 그 가치가 빛 바라지 않을 것이며 C와 C++을 배우면 다른 언어를 배우고 이해하기에 상대적으로 쉽다는 장점도 있다.

따라서 지금 이 시점에서 과연 C를 배우는 것이 의미가 있을까? 라는 의문을 가진 분들을 위해 간단하게 C 언어를 소개하고 어떻게 공부해야 할 것인가에 대해 글을 써본다.


1. C의 역사

왠 뜬금없는 역사부터 시작인가? 라고 하시는 분도 있겠지만 사실 프로그래밍 언어를 이해하는 측면에 있어서 역사를 알고 공부하는 것과 모르고 공부하는 것은 차이가 크다. 역사를 알면 C가 왜 이렇게 구현될 수 밖에 없었는지 개발자의 의도를 파악할 수 있으며 이를 통해 언어의 철학을 이해하고 공감할 수 있고 또한 코드에 녹여서 적용할 수 있게 된다. 이는 개발자의 실력을 가늠할 수 있는 중요한 지표가 되기도 한다.


좌 : 켄 톰슨, 우 : 데니스 리치


C언어가 개발될 수 있었던 배경을 말할 때 언제나 가장 먼저 언급되는 것은 바로 UNIX 운영체제이다. 1970년대에는 일반적으로 대부분의 시스템을 어셈블리어로 구현하였는데 이는 HW의 성능이 떨어지기도 했고 당시에 개발되었던 포트란이나 알골 같은 언어들이 OS를 기반으로 하기에는 부족했기 때문이다. 또 다른 배경으로는 당시에 어떤 프로그램을 개발할 때 해당 플랫폼을 기반으로만 개발하여 다른 플랫폼으로의 이식성이 매우 떨어졌고 이로 인해 코드를 수정하는데 많은 시간을 할애할 수 밖에 없었던 문제점도 있었다.

이러한 부분들로 인해 기존의 UNIX 운영체제는 유지보수가 매우 힘들었고 이를 해결하기 위해 당시의 AT&T Bell lab 에서 일하던 데니스 리치(Dennis Ritchie)가 개발한 것이 바로 C언어 이다. 사실 데니스 리치는 켄 톰슨(Ken Thompson)과 함께 UNIX를 개발한 공동 창시자이기도 한데 위에서 언급했던 문제점들을 해결하기 위해 개발하다 보니 자연스럽게 운영체제의 언어적 개념들과 철학이 C에 녹여졌다. 때문에 C언어는 하드웨어의 기본적인 측면을 잘 지니면서도 간결하고 명확한 언어로 개발되었으며 하드웨어의 기능을 바로 바로 맵핑 시키기 때문에 높은 성능 속도를 보여주고 최적화가 뛰어나다. 후에 데니스 리치는 UNIX 운영체제의 어셈블리어 코드를 C언어로 다시 재작성하여 UNIX가 다양한 하드웨어에서 사용될 수 있도록 하였다. 추가적으로 개발자라면 누구나 알고 있는 Hello, World! 또한 데니스 리치가 가장 먼저 사용했다.



위 그림은 C언어의 발전 과정이다. 초기에 미완성 프로젝트였던 CPL을 마틴 리차드가 BCPL(Basic CPL)로 발전시켰고, BCPL이 아직 문법적으로 완성도가 떨어지자 이를 켄 톰슨이 B언어로 개량했다. 그리고 이를 이어받아 대니스 리치가 C언어를 개발하게 된다. C언어 이름의 기원에 대해서는 여러가지 추측들이 많은데 단순히 B에서 파생된 언어라서 다음 글자인 C가 되었다는 소리도 있고 가장 먼저 CPL 프로젝트를 주관했던 크리스토퍼 스트레이치의 이름에서 C를 따왔다는 이야기도 있다. 


2. ANSI / ISO

C가 처음 개발된 직후에는 문법에 대한 명확한 규제가 없었다. 규제가 없다 보니 각기 다른 컴파일러와 플랫폼에서 서로 다른 코드가 동작하는 상황이 벌어졌고 이는 C언어의 호환성과 이식성을 매우 떨어뜨리게 되는 결과를 낳았다. 때문에 문법을 표준화하고 재정비할 필요성이 생기게 되어 1983년 ANSI(American National Standards Institute) 미국표준협회에서 C언어에 대한 표준 위원회를 만들었으며 표준이 완성된 89년의 연도를 따 C89 라고 명명했다. 그리고 다음 연도인 90년에는 국제 표준에 채택되어 ISO 국제표준협회에서 ISO/IEC 9899:1990 를 완성하였으며 마찬가지로 C90이라 부른다. 우리가 C언어를 처음 배울때 사용했던 컴파일러의 대부분이 모두 ANSI C 인 C89 이며 사실 모두 동일한 표준이기 때문에 ANSI C = C89 = C90 이라고 생각하면 된다. 최근에는 좀더 개량된 C99 를 표준으로 사용하는 컴파일러의 수가 늘고 있고 현재 C11까지 완성되긴 했지만 C11의 경우 아직까지는 사용되는 곳이 적다.

개인적으로 C언어를 공부할 때 표준을 같이 공부하는 것은 매우 중요하고 생각한다. 표준을 알고 프로그래밍을 하게 되면 주어진 환경의 컴파일러와 플랫폼에 최적화된 코드를 짤 수 있으며 다른 환경에 맞춰 코드를 수정하거나 이식하기도 어렵지 않다. 반면에 표준을 모르고 접근하게 되면 어디서 버그가 발생하는지 알기 어렵고 표준에 어긋나는 코드들을 일일이 수정하기도 매우 번거롭게 된다.

물론 지나치게 표준을 강조하거나 융통성 없게 최신 표준만 고집하라는 말은 아니다. 표준은 표준일 뿐 그 자체가 기존의 문법을 뒤흔드는 새로운 법칙이 되거나 하지는 않는다. 단지 올바른 표준을 C언어를 배울 때 같이 공부하게 된다면 주어진 환경에 맞춰 보다 간결하고 최적화된 방식으로 접근할 수 있을 것이며 다른 개발자들과의 협업에 있어서도 정해진 표준에 입각하여 효율적이고 생산적인 프로그래밍이 가능할 것이다. 


3. 현재의 C

그럼 다시 처음의 질문으로 되돌아가보자. 지금 시점에서 C를 공부해야하나? 당연히 공부하면 좋다. 하지만 아닐수도 있다고 생각한다. 이게 무슨 뚱딴지 같은 소리인가 하면 이 물음에 정답은 공부하는 본인에 달려있다는 이야기이다. 필자도 개인적으로 C와 C++을 익히지 않고는 개발자로서의 깊이 있는 학습이 불가능하다고 생각하는 주의였는데 사실 이러한 생각을 가지기에는 시대가 너무 다양화되는 방향으로 발전해버렸다. 더이상 C를 모르더라도 웹이나 앱을 개발할 때 거의 지장이 없고 분야에 따라서는 평생 LOW 레벨에서 프로그래밍할 일이 없을 수도 있다. 또한 하드웨어의 성능이 높아지면서 C에서 가능한 일들의 대부분은 다른 언어로도 구현이 가능해졌다. 요컨대 C의 쓰임새가 현대에 들어서 많이 줄었을 뿐만 아니라 C의 고질적인 단점인 안정성 문제를 해결하고 더욱 더 생산성 높은 언어로 대체가 가능해졌다는 것이다. 본인의 분야와 앞으로의 미래를 두고 봤을 때 굳이 C가 필요 없다면 공부하지 않아도 상관없다.

하지만 앞서 언급했던 모든 부분들을 고려해 보아도 여전히 C언어를 배우는 것은 도움이된다. 공부하지 않아도 상관없다는 말은 필요성에 대한 답일 뿐 절대 그 본질적인 의미까지 퇴색되진 않기 때문이다. C언어가 진입장벽이 높고 불편한 것은 사실이지만 반대로 이 때문에 배우는 입장에서 더 유연하게 프로그래밍하는 법을 배울 수 있다. 거기에다가 하드웨어를 직접적으로 다루기 때문에 컴퓨터 아키텍쳐에 대해 보다 깊숙히 파고들 수 있으며 특히 OS를 이해하는데 있어서 도움이 될 수 밖에 없다. 세세하게 들어가면 소프트웨어의 가장 기본 단위인 bit부터 시작해서 메모리 관리, 구조체 등 전반적으로 다른 언어들의 기초가 되었던 개념들을 모두 배우기 때문에 시야를 넓게 보기 좋으며 이러한 부분들로 인해 타 언어 학습에 대한 이해도가 빠르고 그만큼 숙련도가 높아질 수 있다. 배움에 있어서는 본인이 선택할 문제이지만 C를 배워서 후회될 부분이 전혀 없다는 것이다.

앞으로도 C는 성능이라는 측면에서 절대 무시할 수 없는 언어이기 때문에 지속적으로 많은 분야에 활용되게 될 것이다. 당장 현시점만 놓고 봐도 C는 모든 아키텍쳐와 운영체제에서 1순위로 지원하고 있으며 자바의 경우에도 가상머신인 JVM 자체가 C와 C++로 만들어져 있어 속도가 필요한 모든 코어 부분에서 C가 활용되고 있다. 어떤 의미에선 사실상 C언어가 가장 완벽한 멀티 플랫폼을 지원한다고 해도 과언이 아니다. 그러므로 오래된 언어라고 전망 자체가 어둡거나 그러진 않으며 모든 언어의 베이스가 되는 C를 배우는데 주저하지 말고 자부심을 가졌으면 하는 바람이다.


4. 추천 서적

마지막으로 C언어를 배우면서 필자가 괜찮다고 생각한 책 몇 권을 추천하는 것으로 본 포스팅을 마치도록 하겠다. 사실 안타깝지만 우리나라에는 표준을 준수하는 C언어 책을 찾아보기 매우 힘들다. 아니 거의 없다고 봐도 무방하다. 또한 대부분이 입문 수준에 맞춰져 있기 때문에 내용이 비슷하고 어떤 책을 보든 비슷한 느낌을 받을 수 밖에 없다. 그러므로 입문 서적을 고를 때는 서점에 가서 개인 취향에 맞게 읽기 쉬운 책을 구매하기를 바란다. 개인적으로는 윤성우의 열혈 시리즈가 설명이 자세하고 보기 편했으며 최호성의 독하게 시작하는 C 프로그래밍은 내용과 수준이 괜찮았던 것 같다. 두 책 모두 동영상 강의가 있기 때문에 처음에 접근하기도 수월하다. 


              


C언어에 대해 기본적인 지식을 갖게 되었다면 다음은 해외에서 가장 검증된 책들을 읽기 권한다. 원서이기는 하지만 IT 분야의 책들은 키워드만 알고 있어도 내용을 이해하기 어렵지 않기 때문에 그다지 겁먹을 필요가 없다.



먼저 왼쪽 책은 앞서 C언어의 역사를 소개하면서 언급했던 데니스 리치 이름이 나온다. C언어의 창시자가 책을 썼으니 그 수준이 어느정도인지는 따로 말하지 않겠다. 그리고 여기서 브라이언 커니핸이라는 이름을 잘 기억해두자. 브라이언 커니핸은 UNIX로 변경되기 전 UNICS 라는 이름을 가장 먼저 사용한 인물로 C언어 개발에 직접적으로 참여하지는 않았지만 UNIX 와 C의 발전에 큰 역할을 하였다. 그의 코드와 글은 명료함의 본보기라 불리는데 책을 보면 알겠지만 예제 코드가 정말 간결하고 필요없는 코드가 거의 없으며 정의와 표준에 입각하여 개념을 잘 설명해준다. 저자의 이름을 따서 KNR 이라고 불리며 너무 간결한 나머지 이해하기 어려울 수 있으므로 기본이 어느 정도 갖춰진 상태에서 보기를 권한다. 어투가 딱딱하기는 하지만 번역 상태가 그리 나쁘지 않은 국내 번역본도 있으므로 취향에 맞게 원서든 번역본이든 꼭 구매해서 읽어보도록 하자.

오른쪽 책은 전세계적으로 가장 검증된 C입문 책이다. K.N.King 이라는 분이 쓰신 책인데 C89와 C99의 표준을 서로 비교하면서 상세하게 다루고 있는 것이 특징이며 약간의 자료구조와 함께 Low-level 프로그래밍, 디자인 방식 등 전반적으로 C라는 언어 자체에 대해서 폭넓게 다루고 있다. 아직까지 우리나라에 번역본은 없지만 개념을 정말 상세하게 설명해주기 때문에 원서로 읽어도 큰 무리가 없을 것이다.

마지막으로는 C를 공부하면서 추가적으로 공부하기 좋은 책들을 소개하겠다. 


               


왼쪽의 책은 Richard Reese의 Understanding and Using C Pointers 라는 책으로 제목에서 알 수 있듯이 포인터에 관련된 부분만 추려서 만들어졌다. C언어를 배울 때 가장 어렵게 느껴지는 부분이긴 하지만 그만큼 핵심적인 역할을 하는 포인터에 대해서 이해하기 쉽게 잘 설명해준다. 또한 비단 이 책의 장점이 포인터만 알려주고 끝나는 것이 아니라 보안 이슈와 포인터 남용으로 인한 오버헤드, 댕글링 포인터, 메모리 해제 등 개발하면서 발생할 수 있는 다양한 문제들에 대해서 통찰력 깊은 시야를 제시해주는데 있다. 실무에서 쓰이는 다양한 기법들이 책에 녹아 있으므로 포인터에 대한 이해가 부족하거나 한 단계 깊게 공부하고 싶다면 위 책을 통해 공부해볼 것을 권한다. 번역 상태는 살짝 아쉬운 정도이다.

다음으로 오른쪽 책은 김유진의 임베디드 프로그래밍 C코드 최적화라는 책으로 임베디드 시스템에서 이룰 수 있는 최적화 방법을 제시하며 상세하게 설명해준다. 시간 날 때 가볍게 읽을 수 있는 책처럼 보이지만 사실 그 내용을 들여다보면 초보자가 이해하기에 만만치는 않으며 다른 C언어 책에서는 볼 수 없는 개념과 자료들이 풍부하다. 특히 어려울 수 있는 내용을 과장과 대리의 대화를 통해 쉽게 풀어내기 때문에 임베디드 분야나 코드 최적화 부분에 관심이 많은 사람들에게 도움이 될 것이다.