티스토리 뷰
C언어를 배울 때 가장 먼저 사용하는 함수는 printf()일것이다. 또한 C프로그램에서 가장 많이 불리워지는 함수도 printf()일것이다. 그러나 이렇게 많이 사용하고 있는 printf() 함수가 실제로 어떻게 생겼는지 그 소스를 찾아본적은 거의 없을 것이다.
이번 글에서는 printf() 함수를 라이브러리에서 제공하는 것을 사용하지 않고 직접 만들어 보기로 하겠다.
printf() 함수의 소스 코드는 인터넷에서 검색하면 어렵지 않게 찾을 수 있을 것이다. 이 글에서는 BSD-lite 안에 들어 있는 코드를 참조하였다.
아직 C언어에 익숙하지 않은 프로그래머가 보기에는 소스코드가 다소 복잡하게 보일것이다. 따라서 이 코드를 바로 임베디드 시스템에 적용하기에 앞서 visual studio나 리눅스 환경에서 미리 검증한 후 실제 임베디드 보드에서 확인하는것이 좋다.
아래 코드는 visual studio에서 동작 확인을 위하여 만들어 본 코드이다.
직접 만들어 본 코드에 문제가 없음을 확인하였으면 실제 보드에서 동작 시켜 보도록 하겠다.
먼저 해야 할 일은 이제 더이상 컴파일러에 포함되어 있는 C라이브러리가 프로젝트 빌드시에 포함되지 않도록 하기 위하여 Makefile을 수정하여야 한다.
6번줄에 있는 -nostdinc 옵션을 이용하여 라이브러리에서 제공하는 include 파일을 사용하지 않겠다는것을 알려 준다. 하지만, GCC 컴파일러에서 제공하는 헤더 파일은 사용하여야 하기 때문에 -isystem 옵션으로 GCC에서 제공하는 헤더파일을 include 시킨다. GCC 헤더 파일의 위치는 1번줄에서 표현된 방법으로 그 디렉토리를 알 수 있다.
그리고, 링크시에 라이브러리에서 제공하는 코드가 포함되지 않도록 하기 위하여 9번 줄에서처럼 -nostdlib 옵션을 사용하였다.
컴파일과 링크 단계에서 -nostdinc와 -nostdlib 옵션을 주게 되면 더이상 라이브러리에서 제공하는 코드를 사용할 수 없게 되므로 프로그래머가 직접 해당 함수와 헤더 파일을 만들어야 한다.
원본 코드를 참조하여 만들어 본 printf() 함수의 코드는 다음과 같다.
실제 코드를 보면 무척 복잡하다는 느낌이 들것이다.
main()를 위와 같이 만들어서 제대로 동작되는지 확인해 본다. 15번 줄에 보여지는 코드가 제대로 표현되는지 실행하여 그 결과를 확인한다.
Count 값이 100에서부터 1씩 감소하여 0이 되고, 그 다음에 -1이 되는것을 확인할 수 있다.
프로젝트에서 사용된 코드들은 아래에 첨부 하였다.
소스코드를 열어보면 알겠지만 그동안 라이브러리에서 제공하여 그냥 불러 썼던 코드들이 모두 들어 있다. 이번 프로젝트에서는 물론 printf() 함수를 사용하는데 필요한 코드만 들어있다. 다른 함수들이 필요하면 그 코드들도 직접 만들어야 한다.
그렇다면 C에서 제공하는 라이브러리를 그냥 쓰면 되지 굳이 이렇게 불편하게 직접 만들 필요까지 있을까?
그 이유는 다음과 같다.
첫째, 이미 앞의 글에서도 얘기 했다시피 라이브러리코드가 포함되면 프로젝트의 실행 파일 크기가 상당히 커지게 된다. ROM이나 RAM 크기가 충분하면 문제될게 없겠지만 MCU와 같이 ROM과 RAM 크기가 불과 몇K바이트나 몇십K바이트일뿐인 경우에는 라이브러리가 포함됨으로써 전체적으로 커지게 되는 실행 파일의 크기에 민감해 질 수밖에 없다. 어떤 경우 불과 몇십바이트 크기가 아쉬울때가 있기 때문이다. 이런 경우 라이브러리를 사용하지 않고 직접 필요한 함수만 만들어 쓰게 되면 그 크기를 대폭 줄일수 있게 된다.
둘째, 라이브러리 내부를 알 수 없으므로 원하는 동작이 수행되지 않을때 그 원인을 찾기가 쉽지 않은 경우가 있다. 때로는 보드에 맞지 않게 동작되는 라이브러리 코드가 포함될 수 있기 때문이다. 프로그래머가 직접 라이브러리를 만들어 쓰게 되면 어느 정도는 디버깅이 가능할 수 있게 된다.
세번째 이유는 프로젝트와는 직접적인 관계는 없지만 라이브러리 코드를 직접 만들어 봄으로써 프로그래밍 능력이 높아지게 된다. 좋은 글을 쓰기 위해서는 좋은 책을 많이 읽어야 하는것처럼 좋은 프로그램을 짜기 위해서는 좋은 코드들을 많이 분석해 보아야 한다. C 라이브러리 코드들은 거의 프로그램의 신들이 만들기 때문에 거의 예술에 가까운 코드들이다. 평소에 절대 사용하지 않는 프로그래밍 기법들을 볼 수 있고, 특히 #define을 이용한 매크로 코드들을 보면 감탄하지 않을 수 없다.
단순히 취미가 아닌 프로그래머를 직업으로 삼으려하는 초보 프로그래머가 있다면 틈틈히 라이브러리 코드를 공부하기 바란다.
'ARM Cortex-M' 카테고리의 다른 글
Cortex-M3 RTOS (0) | 2017.03.25 |
---|---|
heap 메모리 이해 (1) | 2017.03.17 |
interrupt (0) | 2017.02.25 |
System Timer (0) | 2017.02.24 |
UART - STDIO (5) | 2017.02.18 |