C언어를 독학으로 공부한 이야기와 C 언어를 공부해야 하는 이유

Posted by taeho Tae-Ho
2014.02.28 18:34 나의 생각

오늘...사무실의 사물함을 열었다가 우연히 눈에 띈 책 한권. 컴퓨터의 매력에 끌려 막연하게 갖고 놀던 컴퓨터를 제대로 이해하고 본격적으로 SW의 세계에 발을 담그게 해준 바로 그 책이 눈에 띄었다. 20년이 지나도 버리지 못하는 책... C언어에 입문하게 해준 바로 그 책이다.


GW베이직, 퀵베이직, 파스칼(터보)을 거쳐 공부하게 된 C언어. 물론 누군가에게 가르침을 받아본 적은 없다. 그냥 홀로 공부했을 뿐이다. 그 중에서도 C언어는 가장 매력있는 프로그래밍 언어였다. 군 입대 전 대학 1학년에 난 별 생각없이 대학시절을 즐기던 대부분의 대학 초년생들과는 달리 컴퓨터에 푹 빠져 있었다. 혼자 프로그래밍을 공부했고 z80, 8088 등의 마이크로프로세서 관련 책을 사서 읽기를 즐겼고 마이크로프로세서가 어떻게 메모리에 프로그램을 로드하고 어떻게 명령코드들을 인출해 레지스터에 올리는지, 마이크로프로세서가 메모리를 어떻게 액세스하는지, 인터럽트가 발생했을 때 마이크로프로세서가 인터럽트를 어떻게 처리하는를 이해하려 머리를 싸매고 있었다. 


그렇게 재미있게 1년을 컴퓨터에 투자하고 현역으로 군복무를 하게 되면서 한동안 컴퓨터를 만질 수 없었다. 그리고....


군 입대 후 1년 여가 넘은 어느 날(상병을 달고 몇 개월 후) 내가 근무하던 우면산에 새로운 통신장비들이 들어오며 계측기가 하나 딸려왔다. 덩치가 무척 큰 계측기였는데 계측기의 커버를 여는 순간 내 눈은 똥~그래 졌다. 커버를 열고 커버의 안쪽을 보니 키보드가 달려 있었다. 그리고 작은 (아마도 7인치가 조금 안되는) 모니터 그리고 플로피디스크드라이브와 HDD 램프로 보이는 LED... 순간 "그래 이거야... 하느님께서 내게 선물을 주신거야~"라는 생각이 들었고 다음 번 외박 때 C언어 책 하나와 플로피디스크에 터보씨를 담아 복귀 했다.


그리고 그 계측기에 터보씨를 설치하고 (계측기에 당시에 처음 사용해본 20M HDD가 달려 있었다.) c 언어를 공부하기 시작했다.




C 포인터의 세계에 빠지다.


내가 c 언어를 공부하면서 가장 먼저 접근한 것은 바로 포인터(pointer)다. 마이크로프로세서와 메모리 등을 공부하다 보면 메모리에 대한 개념이 일반적인 프로그래밍 공부를 할 때와는 차원이 다른 형태로 다가오기 때문에 포인터에 관심이 무척 많았었다. 그리고 다른 언어를 통해 프로그래밍의 흐름과 제어문, 반복문의 구조에 익숙하기 때문에 c 언어의 문법에 적응하는 것은 시간문제였고 다른 언어에는 없는 포인터에 대한 공부가 가장 시급하다고 생각되었기 때문에 포인터 관련 책을 구입하여 c언어를 공부하기 시작했다.


베이직, 파스칼 등 내가 공부한 다른 언어들은 포인터 개념이 없었다. 최근 SW개발에 가장 많이 사용되는 자바에도 포인터의 개념은 없다. 자바 개발자들은 레퍼런스라는 개념을 포인터와 같은 것이라고 이야기하지만 개념적으로는 유사하나 실질적으로 코드 내에서 사용하는 방법이나 참조방법, 접근방법 등은 c언어의 포인터가 훨씬더 로우레벨로 접근해야하고 메모리에 대한 보다 세밀한 핸들링이 가능하기 때문에 사실 비교할 바가 못 된다.



C 언어에서 포인터를 빼고 프로그래밍을 논할 수 없는 이유는 바로 c 언어에는 string 이라는 개념이 없기 때문이다. 다른 언어들을 공부한 사람들이 C 언어를 접하면서 가장 난해해하는 것 중 하나가 C 언어의 느슨한 데이터 타입에 대한 제약이다. 그리고 "문자열(string)" 데이터 타입의 변수가 없다는 것에 당황스러워하곤 한다. 때문에 문자열의 입력과 처리(비교, 자르기, 복사, 출력, 입력)에 필요한 함수들을 모두 직접 개발자가 만들어야 한다. 그렇게 만든 함수들은 library로 만들어 다른 프로그래밍에서도 계속 사용하곤 한다.


C언어에서 문자열을 처리하기 위해서 필수적으로 필요한 것이 바로 포인터다. 즉 메모리를 할당 받고 할당받은 메모리의 시작주소를 포인터 변수에 넣은 뒤 부터 포인터의 위력은 발휘된다. 메모리의 번지 하나하나를 직접 액세스하는 코드를 작성하며 모든 데이터를 처리해야 하지만 그 속도는 타 언어가 절대 따라오지 못하는 빠른 속도를 내기 때문이다.


포인터를 공부하다 보면 구조체의 포인터, 함수 포인터, 포인터의 포인터 등 매우 다양하게 포인터를 사용할 수 있음을 알게된다. 참 매력있는 프로그래밍 언어임을 느끼면서 동시에 "어렵다"는 벽을 느끼게 하는 것이 바로 포인터다.


1992년 가을 쯤 구입한 Mastering C Pointers 라는 책. 나의 군복무 후반기를 즐겁게 해준 c 언어 책이다. 처음부터 끝까지 오로지 포인터를 주제로 씌어져 있는 책이다. 덕분에 프로그램의 메모리 할당과 액세스 방식 등에 대해 자세히 알게해준 책이다. 하긴..제대할 때까지 이 책을 보고~또보고~했으니..



C 언어와 포인터를 공부해야 하는 이유


프로그래밍의 세계에서 끊임 없이 논쟁이 되는 것 중 하나가 Java와 C 중 어느 언어가 더 우월한가에 대한 것이다.  얼마전 안드로이드와 IOS의 비교에서 IOS가 속도 및 안정성 우월하다는 투의 포스트를 올린적이 있다. 엄밀하게 이야기한다면 안드로이드가 자바의 바이트코드기반이고 IOS는 C가 컴파일된 네이티브코드 기반이어서 IOS가 가볍고 빠르다~ 그래서 안드로이드가 IOS를 이기기 힘들다는 논조의 포스트였다.  그런데 뜻밖에도 많은 안드로이드 기반 자바 개발자들이 달려들어 내 포스트에 논리적인 비판보다는 비난의 댓글을 다는 일이 있었다.


왜 그런 일이 생겼을까?


최근에는 옛날과 달리 C언어나 운영체제의 깊은 이해 없이 바로 java나 웹 프로그래밍를 배우는 경우가 대부분이다. 그래선지 운영체제가 어떻게 프로그램을 로드하고 실행을 시켜주는지, 애플리케이션이 어떻게 메모리를 할당받고 초기화하며 어떻게 할당받은 메모리의 특정 번지에 있는 데이터를 인출하는지, 도대체 CPU는 무엇으로 구성되어 있고 어떻게 동작하는지 등에 대한 심도있는 이해가 부족한 상태에서 애플리케이션을 개발한다.


일례를 들면....


c언어를 제대로 공부한 개발자들은 배열을 선언하거나 메모리를 할당받을 때 8의 배수, 16의 배수, 32의 배수 등으로 메모리를 관리하고 선언하는 변수도 메모리를 정렬하여 선언하고 할당 받아야 한다고 배우는 경우가 많았다. 하지만 메모리와 포인터 그리고 운영체제에 대한 개념이 제대로 정립되지 않은 개발자들은 배열이나 객체를 선언하고 내부에 변수, 구조체 등을 선언할 때 10, 20, 100, 200 과 같이 십진수 기준으로 아무생각없이(?) 선언하고 메모리를 할당 받는 경우가 많다. (사실 그래도 문제가 발생하지는 않는다.)


하지만 프로그램이 내부적으로 동작할 때 변수의 크기에 따라 정렬하여 선언하고 메모리 할당을 8의 배수, 16의 배수, 32의 배수 크기로 할당받았을 때 가장 최적화된 상태로 메모리를 사용한다. 당연히 프로그램의 동작과정에서 발생하는 오버헤드도 적을 수 밖에 없다. 물론 하드웨어 성능이 크게 발전한 요즘 체감속도에서는 별차이를 느끼지 못할 수 있으나 CPU의 클럭이 2G~3G hz에 달하는 상황에서 해당 프로그램이 소비하는 CPU 사이클 수의 차이는 무척 큰 것이 사실이다. 눈에 보이는 속도의 차이가 작다해서 결코 비슷한 속도는 아닌 것이다. 


아마도 프로그램에서 메모리를 어떻게 할당 받아 사용하느냐가 뭐가 그리 중요하냐고 따질 수도 있다. 하지만 수많은 프로그램이 실행되는 운영체제의 전반적인 입장에서 개별 프로그램들의 중구난방식 메모리 할당과 사용은 골칫거리가 될 가능성이 높다. 운영체제의 경우 메모리 단편화로 인해 페이지스캔 부하가 증가할 수 있고 Java의 경우 가비지컬렉션 부하가 증가할 수도 있다.


C 언어를 공부하면서 포인터를 함께 공부하여 프로그램 내에서 포인터가 어떻게 쓰이는지와 메모리의 할당과 액세스 그리고 해제에 대해 이해를 하게 된다면 java 개발자라 하더라도 운영체제의 메모리관리와 프로그램의 동작에 대해 깊이있는 이해를 갖고 애플리케이션을 개발을 할 수 있을 것이다. 


난 네트워크 운영자, 서버 운영자, 개발자, 그리고 여러 솔루션 엔지니어도 c 언어를 공부할 것을 권한다. 운영체제도 대부분의 코드가 c 언어로 개발되었고 네트워크 장비의 sw도 c 언어로 만들어져 있다. 심지어 java 도 c로 만들어져있을 것이다. 웹서버, DBMS 등도 당연히 c 언어로 개발되어 있다. c 언어를 이해하면 그 수많은 sw를 이해하고 운영하고 트러블슈팅을 하는데 정말 큰 도움이 되는데 많은 개발자나 엔지니어가 그러한 점을 간과하고 있는 것이 무척 안타깝다.


개발자, 운영자, 엔지니어들은 모두 C 언어를 공부하는 것이 큰 도움이 될 것이다.


관련포스트가기 : 메모리 부하 테스트 프로그램 작성하기 (c언어, malloc()함수) - 가상메모리의 마술


신고
Tags
이 댓글을 비밀 댓글로