헤더 파일
#include <stdio.h>
int main(int argc,char** argv)
{
printf("Hello World\n");
return 0;
}
main 함수에서는 printf 라는 함수를 호출 했었습니다.
이 함수는 직접 작성한 함수는 아닌, 라이브러리로써 컴파일러 제조사에서 제공해줍니다.
이 함수의 정의는 stdio.h라는 헤더 파일내에 정의되어 있으며,
코드를 작성할때 적었던 #include <stdio.h> 전처리 구문에 의해 참조됩니다.
- <> 는 프로젝트 및 환경변수에 설정된 경로로부터의 탐색이며,
- "" 는 현재 소스코드가 위치한 디렉토리로부터의 탐색입니다.
불러오는 파일의 확장자는 주로 .h를 사용하며 헤더파일이라는 의미를 갖습니다.
C++의 헤더파일 정의에서는 .h를 붙이지 않도록 정의하고 있지만, 아직 많은 프로그래머들은 .h의 확장자를 사용하고 있습니다.
목적코드
위 이미지는 지난번에 작성했었던 Hello World 프로젝트의 폴더입니다.
Debug(혹은 release)라는 폴더 밑에, main.obj 라는 파일을 보실 수가 있습니다.
이 파일이 main.cpp 가 기계어(목적코드, object code)로 변환된 모습입니다.
- 목적코드는 각각의 함수들을 각각 하나의 기계어 집단으로 번역해놓은 코드입니다.
- 이 단계까지는 각각의 함수들을 번역하는 과정이기 때문에 다른 함수와의 호출관계는 고려되지 않습니다.
- 컴파일러마다 다릅니다만, Visual Studio 의 C/C++ 컴파일러는 소스코드 파일 하나당 하나의 중간 object 파일을 생성합니다.
int func(int value);
위처럼 구현부가 없이 정의만이 존재하는 함수는, "이런 함수가 어딘가에 존재할 것이다"라는 사실을 컴파일러에게 알려줍니다.
- 실제 구현부는 같은 소스코드(동일한 목적코드 파일) 내부에 있을수도 있고, 혹은 다른 목적코드 파일에 들어있을 수도 있습니다.
- 일단 이 정보가 있다면 설령 함수 실체가 어디에도 존재하지 않더라도, 이 소스코드는 목적코드로 컴파일 할 수 있습니다.
링커는 이러한 목적코드들을 모아 최종적인, 하나의 실행파일로 만들어 냅니다.
- 하나의 실행파일로 만들어 낸다는 것은 각 목적코드들을 적당한 위치에 배치하고, 그들의 호출관계를 확립한다는 의미를 가집니다.
main 함수에서 printf 함수를 사용할 수 있었습니다. 이는 stdio.h에 그 함수에 대한 정의가 포함되어 있기 때문입니다.
그리고 이 printf 함수에 대한 목적코드는 OS가 제공하는 목적코드 파일에 포함되어 있습니다.
- "stdio.h" 파일은 표준 입출력에 대한 함수들의 정의를 담고 있고 있으며, 구현은 OS 에서 제공하는 object 파일에 기계어의 형태로 포함되어 있습니다.
- main.c파일 에서는 stdio.h 파일을 참조하고 있으며, 해당 파일에 포함되어 있는 함수의 정의들이 포함되었다고도 할 수 있습니다.
링킹
목적코드들을 하나의 실행파일로 모으면 목적코드에 "위치"가 생깁니다.
- 0번부터 10번까지 main 함수를 배치했다면, 11번부터 20번 혹은 다른 어떠한 위치에 printf 함수를 배치해야 합니다.
- "위치"가 생기면서, 비로소 함수간의 호출관계를 확립할 수 있게 됩니다.
- main 함수에서 printf 함수를 호출하려면 printf 가 어디에 위치해 있는지 알 필요가 있기 때문입니다.
링킹 과정에서 함수의 목적코드를 찾을 수 없다면 링킹 에러가 발생합니다.
이후 운영체제가 이 파일이 실행 가능한 파일임을 알 수 있도록, 몇 가지 추가 정보를 덧 붙여 파일에 기록한 뒤, 만들어낸 결과물을 기록합니다. 결과물은 일상적으로 말하는 실행파일입니다.
- 실행파일에도 규격이 있습니다. Windows 에서는 PE 라는 파일 포맷을, Linux 에서는 ELF 를 사용합니다.