본문 바로가기

C++/C, C++, STL

헤더(Header) 파일과 소스 파일 분리

더보기

C++의 컴파일러는 .cpp 파일을 독립적인 단위로 컴파일합니다.

따라서 컴파일러는 다른 컴파일 단위에서 처리된 변수 함수 클래스와 같은 이름을 알지 못합니다.

즉, 어떤 cpp 파일이 다른 cpp 파일에서 정의하는 요소의 이름을 알기 위해서 해당 항목의 선언을 제공해야 합니다.

헤더 파일과 소스 파일 분리

.h 확장자로 작성되는 헤더 파일은 어떤 요소의 정의를 포함합니다.

다음은 헤더 파일을 작성하는 example.h 예시입니다.

namespace ExampleNamespace
{
    class ExampleClass
    {
    public:
        void doSomething();
    };
}
코드 비고
Line 1 namespace ExampleNamespace 헤더 파일을 구성하고 요소의 정의를 네임스페이스에 포함시킵니다.
Line 3:7 class ExampleClass { } 헤더 파일이 정의하는 요소입니다.

.cpp 확장자로 작성되는 소스 파일은 어떤 요소를 구현하기 위한 코드를 포함합니다.

이때 다른 헤더 파일의 정의를 참조하려면 #include 키워드를 사용합니다. #include는 로컬 디렉토리 또는 표준 라이브러리를 포함합니다.

다음은 헤더 파일의 정의를 구현하는 example.cpp 예시입니다.

#include "example.h"
#include <iostream>

using namespace ExampleNamespace;

void ExampleClass::doSomething()
{
    std::cout << "Hello World!" << std::endl;
}
코드 비고
Line 1 #include "example.h" 로컬 디렉토리의 헤더 example.h를 참조합니다.
Line 2 #include <iostream> 표준 라이브러리 헤더 iostream을 참조합니다.
Line 4 using namespace ExampleNamespace 요소의 이름을 사용할 때 네임스페이스를 생략합니다.
Line 6:9 void ExampleClass::doSomething() { } 예제의 헤더 파일 example.h가 정의하는 ExampleClass의 함수를 구현합니다.

헤더 파일 example.hexample.cpp가 구현합니다. 이제 다른 .cpp 파일이 이 클래스 정의를 사용 할 수 있습니다.

#include "example.h"

int main()
{
    ExampleNamespace::ExampleClass c;
    c.doSomething();
}

가드(Guards) 포함

일반적으로 헤더 파일에는 단일 .cpp 파일에 여러 번 포함되지 않도록 include guard 또는 #pragma once 지시문이 있습니다.

일반적인 헤더 중복 사용 방지는 다음과 같은 가드 사용입니다.

#ifndef HEADER_H
#define HEADER_H

// todo: somethings

#endif
코드 비고
Line 1:2 #ifndef HEADER_H HEADER_H 심볼이 정의되어 있지 않은 경우 다음 코드를 실행합니다.
#define HEADER_H HEADER_H 심볼을 정의하고 헤더를 정의합니다.
Line 6 #endif HEADER_H 심볼이 정의되어 있다면 헤더를 정의하지 않습니다.

심볼은 일반적으로 헤더 파일의 이름을 대문자로 치환한 결과이지만 중요하지는 않습니다.

즉, 헤더 파일이 다른 .cpp 파일에 처음 포함될 때 심볼의 유무에 따라서 헤더 파일을 처음 정의하거나 건너뛰도록 합니다.

이를 예제에 적용하면 다음과 같습니다.

#ifndef EXAMPLE_H
#define EXAMPLE_H

namespace ExampleNamespace
{
    class ExampleClass
    {
    public:
        void doSomething();
    };
}

#endif

위와 같은 include guard는 오래전부터 사용된 방법이며 모든 컴파일에서 동작한다는 장점이 있습니다.

#pragma once

헤더 파일의 또 다른 중복 방지는 #prama once입니다.

#pragma once

// todo: somethings

한 줄만으로 include guard와 동일한 역할을 하며, 별도의 심볼을 명명하지 않고도 때때로 컴파일 속도가 빠르다는 장점이 있습니다.

더보기

#pragma once는 C++ 표준이 아니기 때문에 일부 지원하지 않는 컴파일러도 존재합니다. 따라서 호환성 및 성능 향상 면에서는 두 가지 중복 방지 가드를 동시에 사용 하는 것을 권장합니다.

#pragma once
#ifndef HEADER_H
#define HEADER_H

// todo: somethings

#endif

정리 및 복습

  • 헤더 파일 .h는 어떤 요소를 정의합니다.
  • 소스 파일 .cpp는 헤더 파일을 포함해 어떤 요소를 구현하거나 이를 사용해 코드를 작성합니다.
  • 헤더 파일의 중복 정의를 방지하려면 include guard 또는 #pragma once 지시문을 사용합니다.
  • #pragma once는 사용이 간편하고 컴파일 속도에서 유리하나 일부 컴파일러에서 지원하지 않습니다.
  • 따라서 두 가지 가드를 동시 사용하는 것을 권장합니다.