TEUS.me

 
 

C/C++ 언어에서 헤더의 중복 선언을 방지하기 위해 #pragma once[각주:1]를 사용한다.

그런데, #pragma once를 써도 링크 오류가 발생하는 경우가 있다.

 

아래와 같은 간단한 프로그램들을 보자.

 

// CTest1.h: 헤더 파일
//

#pragma once

class CTest1
{
public:
	int Func();
};

 

// CTest1.cpp: 클래스 동작을 정의함
//

#include "CTest1.h"

int CTest1::Func() {
	return 1;
}

 

#include <iostream>

#include "CTest1.h"

int main()
{
    CTest1 test1;

    std::cout << test1.Func() << std::endl;
}

 

물론 이 코드는 정상적으로 동작한다.

 

 

그런데, 어떤 이유로 다음과 같이 변형하게 될 일이 생겼다고 하자.

 

// CTest1.h: 헤더 파일
//

#pragma once
class CTest1
{
public:
	int Func();
};

CTest1 test1;

 

#include <iostream>

#include "CTest1.h"

int main()
{
    std::cout << test1.Func() << std::endl;
}

 

이 코드에서만 보면 저렇게 쓸 일은 없겠지만, 실제로 비슷한 경우는 종종 발생한다.

저 클래스의 인스턴스를 하나만 생성해서 공유해야 되는 경우라든지...

 

하지만, 저 코드를 컴파일해보면 다음과 같은 오류가 발생한다.

 

 

코드를 #pragma once로 막아두었지만, 여러 번 정의되었다LNK2005 오류가 발생하는 것이다.

편하게(?) 생각하면 test1이라는 인스턴스를 공유하려고 하는 것 같지만 컴파일러는 그렇게 생각하지 않는다.

메인 함수가 있는 cpp 파일과 CTest1.cpp 에서 모두 CTest1.h 를 include하고, 컴파일 시점까지는 아무런 문제가 없다가 링킹 시점에서 test1 이라는 인스턴스가 중복되어 오류가 발생하는 것.

 

만약 의도가 test1이라는 인스턴스를 다른 클래스 등과 공유하는 것이라면 extern을 활용해야 한다.

 

// CTest1.h: 헤더 파일
//

#pragma once

class CTest1
{
public:
	int Func();
};

extern CTest1 test1;

 

// CTest1.cpp: 클래스 동작을 정의함
//

#include "CTest1.h"

int CTest1::Func() {
	return 1;
}

CTest1 test1;

 

 

  1. 예전엔 #ifdef .. #endif를 썼었음 [본문으로]

공유하기

facebook twitter kakaoTalk kakaostory naver band

댓글

비밀글모드

  1. 전 왠지 #pragma once보다

    #ifndef __어쩌구_저쩌구_H__
    #define __어쩌구_저쩌구_H__

    #endif

    를 늘 선호하더라구요 .. 왠지 #pragma once 하면 정없는 느낌 ㅎㅎㅎ ( 아재인가봅니다 )
    2022.01.05 08:44 신고
    • 아재감성이라기 보다는... 저도 #ifdef 쪽이 더 직관적인 것 같습니다.
      #ifdef로 막을 땐 그냥 컴파일 타임만 되겠구나... 싶었는데, #pragma once로 바꾼 이후엔 왠지 링크 때에도 동작할 것 같은 느낌 같은 게 느껴지기도 하고요... ㅎㅎㅎ
      2022.01.06 11:35 신고