IT 공부/C, C++

[C언어] - 헤더 파일이 필요한 이유

exdus3156 2024. 12. 27. 20:00

 

▷ C/C++에서는 헤더 파일이 필수다. 예전에 C를 처음 배울 때, 헤더 파일을 연결해야 거기에 선언된 함수를 가져다 쓸 수 있는 거라고 생각했다. 틀린 말은 아니지만 이 설명에는 중간 과정이 전부 생략된 것이 문제다.

 

헤더 파일을 연결하면 그 헤더 파일에 있는 함수 선언을 전처리기가 복사/붙여넣기 해준다. 그리고 이것을 컴파일러가 컴파일해서 오브젝트 파일로 만들어주는 것이다. Windows의 경우 COFF 포맷의 파일이 생성된다. 이 과정에서 과연 전처리기나 컴파일러가 헤더 파일에 선언된 함수에 대해 뭘 알고 있을까? 

 

놀랍게도 전처리기나 컴파일러는 선언된 함수에 대해 알고 있는 것이 하나도 없다. 사실 이들은 함수의 내용에 관심이 없다. 예를 들어, <stdio.h>에 있는 printf() 함수를 썼다고 하자. 그러면 전처리기나 컴파일러가 printf()가 stdio.h에 있으니까 C 표준 라이브러리를 호출했다는 사실을 고려할까? 고려하지 않는다. 전처리기는 오직 헤더 파일을 찾아서 붙여넣는 기능을 할 뿐이다. 컴파일러는 소스코드를 가지고 컴파일할 뿐이다. 이때 선언된 함수의 '형식'를 토대로 문법이 올바른지 검사만 할 뿐이다.

 

컴파일러는 헤더 파일의 선언을 토대로 소스코드의 함수 호출이 형식적으로 문제가 없는지만 판단할 뿐이라는 것이다.

 

실제로 호출한 함수의 구현 코드를 라이브러리에서 찾아서 연결해 실행 파일을 생성하는 주체는 링커다. 링커는 라이브러리의 경로 값과 라이브러리 이름을 토대로 호출된 함수를 연결(link)하는 역할을 수행한다. Visua Studio가 링커에게 어떤 라이브러리 경로를 찾아야 하는지, 라이브러리 이름은 무엇인지 미리 세팅해줘서 이 과정이 처음에는 휙 하고 지나간다.

 

이렇게 배우고나서 나는 의문이 들었다. 함수 선언이 오직 호출된 함수의 형식 검사를 위해 존재하는 것이라면, (위험성이 있긴 하겠지만) 검사를 굳이 하지 않아도 되는 것이 아닐까? 만약 호출이 잘못되었다면 링커가 그런 함수는 없다고 발견해주지 않을까 싶었던 것이다.

 

이런 의문이 든 시점은 다른 프로그래밍 언어들을 찍먹했을 때였다. 예를 들어, 자바스크립트는 함수 호출 시 인터페이스를 굳이 검사하지 않기 때문이다.

 

하지만 위와 같은 프로그래밍 언어 스타일의 단점이 그대로 C/C++ 헤더 파일의 장점과 이어진다.

 

일단, 헤더 파일의 함수 선언은 일종의 인터페이스다. 만약 내가 정적 라이브러리를 개발하고 배포한다면 헤더 파일을 같이 배포한다. 이 헤더 파일에는 함수에 대한 인터페이스가 선언되어 있으며, 이 설명은 단순히 문법 검사와 같이 컴파일러 입장에서 유용할 뿐만 아니라, 개발하는 사람 입장에서도 깔끔한 인터페이스 문서가 되는 것이다. 만약 이게 없다면 모든 함수 형식을 외워서 개발해야 할지도 모른다.

 

게다가 링커 단계에서 잘못된 함수 호출을 감지하는 것은 너무 늦다. 컴파일 오류가 좋은 이유는 빨리 문법적인 문제의 원인을 진단할 수 있어서다. 이걸 링커의 역할로 토스해버리면 링커는 단순히 심볼을 연결하는 것뿐만 아니라 문법적 형식까지 처리해야 한다. 아마 링커 프로그램을 대대적으로 손봐야 할 것이다. 또한 컴파일 단계에서 헤더 파일로 간단히 수행될 수 있는 진단을 링커에게 토스하면, 오류 발생 시 또 다시 컴파일해서 오브젝트 파일을 새롭게 손봐야 한다. 이건 너무 번거롭다.