6. 파일과 헤더
1. 파일
보통 프로그램의 코드를 구성할 때, 하나의 파일로 구성하지 않고 여러개로 나누어 구성된다. 이 경우 다음과 같은 장점이 있다:
- 유지보수가 쉬워진다. (파일 단위로 관련 기능들을 묶어서 관리)
- 협업이 용이하다.
- 파일 단위로 코드를 분할해서 컴파일 과정에 문제가 줄어든다.
예를 들어, main.cpp
와 mymath.cpp
두 개의 소스 파일이 있다고 하자.
mymath.cpp
에는 입력받은 정수 _a
부터 _b
까지를 더하는 sum()
함수가 다음과 같이 정의되어 있다.
int sum(int _a, int _b)
{
int sum = 0;
for (int i = _a; i <= _b; i++)
{
sum += i;
}
return sum;
}
이 때, main.cpp
에서 이 함수를 사용하려면 어떨게 해야 할까?
만약 아래와 같이 main.cpp
를 구성한다면 오류가 발생한다.
#include <iostream>
int main()
{
int i = 0;
i = sum(1, 10); //sum() 함수가 정의되어 있지 않다!!
return 0;
}
컴파일 과정에서 컴파일러가 sum()
함수를 찾지 못해서 컴파일 에러가 발생한 것이다.
그렇다고 main()
이 호출되기 전에 sum()
함수 전문을 모두 쓰는 것은 비효율적일 뿐더러, 파일을 분할 한 의미가 사라진다.
이 때, 전방선언을 이용하여 컴파일을 정상적으로 수행할 수 있다.
함수의 전방 선언은 컴파일러에게 “이런 함수가 있다. 내용은? 나중에 알려주겠다.” 라고 선언하는 것이다.
이러한 변수, 함수, 클래스의 선언을 모아서 컴파일러의 컴파일을 돕는 것이 헤더 파일이다.
#include <iostream>
int sum(int _a, int _b); //함수를 전방 선언 해 준다.
int main()
{
int i = 0;
i = sum(1, 10);
return 0;
}
코드를 빌드(Build)하는 과정은 컴파일(Compile)과 링크(Link)로 구성된다. 두 과정이 오류 없이 끝나면, 코드는 실행할 수 있다.
위의 경우, 소스 파일이 2개로 나누어져 있다. 이 경우, 컴파일러는 파일의 컴파일을 각각 진행한다. 독립적으로 진행되기에, 이전에 전방선언 없이는 main.cpp
에서 다른 파일에 있는 sum()
의 함수의 존재를 알 수 없던 것이다.
컴파일 과정이 무사히 종료되면, 링크 과정으로 넘어가게 된다. 아까 전방 선언된 sum()
함수의 내용을 나중에 알려준다고 했었는데, 그 “나중” 이 바로 링크 과정을 뜻한다.
이 때 main.cpp
에서 호출된 sum()
함수의 상세 내용을 확인하고 서로 연결하는 작업을 진행하는데, 이것이 링크(Link)이다.
2. 헤더
헤더, 또는 헤더 파일은 앞서 언급된 것과 같이 “변수, 함수, 클래스의 선언을 모아서 컴파일러의 컴파일을 돕는 것” 이다.
위에서 main.cpp
안의 전방선언은 하나였지만, 파일이 다양하고 호출해야 하는 함수나 변수 등이 많아질수록 코드의 양이 방대해진다.
이를 따로 모아서 하나의 파일에 넣고, 이를 #include
전처리 지시자로 불러와서 컴파일 단계에 집어넣는 것이 헤더 파일의 역할이다.