C++ 분할 컴파일: 헤더 #include 비용과 C++20 모듈 차이 (Tour 3.2)
한 줄 답: C++의 분할 컴파일 방식에서 기존 #include 헤더는 중복 파싱과 의존성 문제를 일으키지만, C++20에 도입된 모듈(Modules)은 단 1회 컴파일과 매크로 격리를 통해 이를 해결합니다.
이 글은 A Tour of C++ 3.2 Separate Compilation 학습노트를 기준으로 정리한 내용입니다. 선언과 정의를 구분하는 3.1의 기본 개념을 가볍게 전제로 삼되, 3.1 내용을 다시 퀴즈처럼 반복하지는 않고 분할 컴파일 방식 자체에만 집중합니다.
헤더를 #include하면 왜 컴파일 비용이 커집니까?
한 줄 답: 여러 소스 파일에서 헤더를 #include할 때마다 텍스트 코드가 그대로 복사되어 반복적으로 파싱되므로 컴파일 시간이 크게 늘어납니다.
헤더 파일(.h)에는 인터페이스 선언을 모아두고, 이를 필요로 하는 소스 파일에서 #include로 불러와 사용합니다. 그런데 #include는 매크로 기반의 텍스트 삽입이기 때문에, 같은 헤더를 여러 소스 파일이 포함하면 그 헤더의 내용이 매번 그대로 복사되어 컴파일러가 매번 처음부터 다시 파싱합니다. 소스 파일 수가 늘어날수록 같은 선언을 반복해서 파싱하는 비용도 함께 늘어납니다.
여기에 더해 두 가지 문제가 따라옵니다. 하나는 순서 의존성으로, #include 순서에 따라 매크로나 선언의 의미가 왜곡되거나 충돌할 수 있습니다. 다른 하나는 전이성(Transitivity)으로, 어떤 헤더가 내부에서 다른 헤더를 포함하고 있으면 그 안의 불필요한 선언과 매크로까지 사용하는 쪽으로 함께 전이(누출)됩니다.

헤더 #include 반복 파싱 비용
C++20 모듈은 헤더와 무엇이 다릅니까?
한 줄 답: 모듈은 파일 단위로 단 한 번만 컴파일되며, 매크로 오염을 차단하고 import 순서에 영향을 받지 않는 안전한 비전이성(Non-transitive) 구조를 가집니다.
모듈은 별도의 파일로 한 번만 컴파일된 뒤 import 키워드로 불러와 사용합니다. 번역 단위마다 반복해서 파싱하지 않으므로 컴파일 속도가 향상됩니다.
모듈은 헤더의 세 가지 문제를 각각 해결합니다. 첫째, 비전이성(Non-transitive)을 가지므로 모듈 내부에서 import한 다른 모듈이 그 모듈을 불러 쓰는 외부 코드로 자동 전이(leak)되지 않습니다. 둘째, 순서 무관성을 가지므로 import 순서가 바뀌어도 의미나 충돌 문제가 생기지 않습니다. 셋째, 매크로 격리를 지원하므로 모듈 내부의 매크로를 외부로 내보내지 않아 이름 오염을 차단합니다.

모듈과 헤더의 차이
헤더 방식과 모듈 방식의 코드 구조는 어떻게 비교됩니까?
한 줄 답: 헤더는 선언을 .h에 두고 소스에서 #include로 텍스트를 불러오지만, 모듈은 export module과 import 키워드를 사용해 필요한 식별자만 명시적으로 노출합니다.
학습노트에 있는 두 방식의 예제를 나란히 비교하면 다음과 같습니다.
// Vector.h
#pragma once
class Vector {
public:
Vector(int s);
};
// Vector.cpp
#include "Vector.h"
Vector::Vector(int s) { /* ... */ }
// user.cpp
#include "Vector.h"
#include <iostream>
int main() { /* ... */ }
// Vector.ixx / Vector.cppm
export module Vector;
export class Vector {
public:
Vector(int s);
};
export bool operator==(const Vector& v1, const Vector& v2) { /* ... */ }
// user.cpp
import Vector;
import std;
int main() { /* ... */ }
헤더 방식에서는 Vector.cpp와 user.cpp 양쪽 모두 #include "Vector.h"로 선언을 텍스트째 불러옵니다. 반면 모듈 방식에서는 export module Vector;로 모듈을 정의하고 export가 붙은 선언만 외부에 공개하며, 사용하는 쪽에서는 import Vector;로 필요한 식별자만 가져옵니다.
FAQ
Q. 모듈의 ‘비전이성(Non-transitive)‘이란 무슨 뜻입니까?
A. 모듈 내부에서 import한 다른 모듈이 해당 모듈을 불러다 쓰는 외부 코드에 자동 누출(leak)되지 않아 불필요한 의존성 전파를 막는 것을 뜻합니다.
Q. C++20 모듈 도입으로 기존 헤더 파일은 더 이상 쓰지 않습니까?
A. 아닙니다. 모듈 시스템은 기존 #include 기반 코드와 완벽히 호환되므로, 기존 프로젝트를 유지하면서 새 기능에 점진적으로 모듈을 적용할 수 있습니다.
출처
C++ 학습노트 — 3.2 Separate Compilation