본문 바로가기
C++ 200제/코딩 IT 정보

[C++구조체] #Pragma Once 사용, 헤더파일 안전하게 사용

by vicddory 2017. 10. 5.

[C++구조체] #Pragma Once 사용, 헤더파일 안전하게 사용


1. 소개


헤더 파일은 프로그램에서 사용할 요소들을 미리 선언하고 정의한 내용을 담고 있습니다. 예를 들면, Class Template의 Layout 정보는 헤더 파일에 정의되어 있고(사용할 변수, 함수 등), Implementation File들은 실제로 함수와 변수들을 구현합니다.


2. #Pragma Once, 헤더 파일 Include


.h나 .hpp의 확장자의 헤더 파일은 #include로 참조할 수 있고, .cpp 파일은 헤더 파일의 선언부 정의 내용을 담습니다. 아래는 선언 예입니다.


1
2
#include "stdafx.h"
#include <conio.h>
cs


3. 두 가지 타입의 Include와 #Pragma Once


사용할 라이브러리는 한 쌍의 괄호 사이(< >)에 넣습니다. 전처리기는 IDE의 경로를 먼저 탐색하고 난 뒤, /I 옵션을 통해 다음 경로도 탐색합니다.


비주얼스튜디오, 추가 포함 디렉터리[C++ 헤더파일 중복방지] MFC 사용 가능


위의 그림은 I 옵션에 대한 설정창입니다("프로젝트 - 속성 - 구성 속성 - C/C++ - 일반 - 추가 포함 디렉터리")

큰 따옴표(" ") 사이의 헤더 파일은 #include 구문을 포함한 파일을 기준으로 합니다. 우선 현재 폴더를 검색해 Include 될 헤더 파일을 찾기 때문에 둘 사이의 Including 과정이 다릅니다.


4. 여러 헤더 파일을 Include 했을 때 문제점과 #pragma Once


#Include는 전처리기로서 컴파일이 일어나기 전에 해당 Statement는 헤더 파일의 내용으로 대체가 됩니다. ab.cpp을 사용하기 위해선, ab.cpp 파일과 이를 선언한 헤더 파일 두 개가 포함된다는 의미입니다. 간단한 예가 아래에 있습니다.


4.1 SimpleMath.h


아래엔 두 개의 간단한 함수를 선언하고 구현한 것입니다.


1
2
3
4
5
6
7
8
9
10
11
12
int Add_Numbers(intint);
int Mult_Numbers(intint);
 
int Add_Numbers(int a, int b)
{
    return (a + b);
}
 
int Mult_Numbers(int a, int b)
{
    return (a * b);
}
cs


4.2 ExtendedMath.h


이 헤더 파일은 두 개의 정수를 받아들이는 함수를 세 개의 정수를 받아들이는 함수로 확장합니다. 파일의 내용은 아래와 같습니다.


1
2
3
4
5
6
7
8
#include "SimpleMath.h"
 
int Add_three_numbers(intintint);
 
int Add_three_numbers(int a, int b, int c)
{
    return ( Add_Numbers(a, b) + c );
}
cs


해설, #Pragma Once


전처리기(컴파일 전)가 동작하는 순간, #Include로 추가되는 헤더 파일들은 컴파일러에 의해 실제 파일의 Content로 변환됩니다. 이는, 컴파일러가 SimpleMath.obj, ExtendedMath.obj와 같은 Object Code를 생성하지 않는다는 의미입니다.


메모리 영역 중, 바이너리 영역에 대해선 관여하지 않는 것이죠.


4.3 CppTest.cpp


Object Code는 어디 있을까요? 함수를 실행할 EXE를 링커는 찾을 수 있을까요?


컴파일러는 CPP 파일에 대한 Object Code를 생성합니다. CPP 파일이 헤더 파일을 Include 할 때, 헤더 파일의 내용으로 Statement가 교체되고, 그 내용이 Object 파일로 이동하면 링커가 EXE 파일을 생성하게 됩니다.


아래는 그 예입니다.


1
2
3
4
5
6
7
8
9
10
// CPPTST.cpp : Defines the entry point for the console application
#include "stdafx.h"
#include "SimpleMath.h"
#include "ExtendedMath.h"
#include <conio.h>
 
int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}
cs


하지만, 위의 CPP 파일을 컴파일하면 아래와 같은 오류가 뜹니다.


error c2048 비주얼스튜디오[C++ 헤더파일 중복방지] MFC 사용 가능


왜 그럴까요?


앞서 설명했듯, #Include는 전처리기의 지시어이며, 컴파일러는 이미 Cpptest.cpp 파일을 실행시키기 위해 SimpleMath.h 파일의 내용을 가져온 상태입니다.


그래서 아래 그림과 같이 동작합니다. #Pragma Once 이해해보죠.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int Add_Numbers(intint);
int Mult_Numbers(intint);
 
int Add_Numbers(int a, int b)
{
    return (a + b);
}
int Mult_Numbers(int a, int b)
{
    return (a * b);
}
 
int Add_Numbers(intint);
int Mult_Numbers(intint);
 
int Add_Numbers(int a, int b)
{
    return (a + b);
}
 
int Mult_Numbers(intint)
{
    return (a * b);
}
 
int Add_three_numbers(intintint);
int Add_three_numbers(int a, int b, int c)
{
    return ( Add_Numbers(a, b) * c );
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}
cs


첫 번째 빨간색 코드 : SimpleMath.h 내용

두 번째 녹색 코드 : SimpleMath.h 내용 (ExtendedMath.h는 SimpleMath.h를 포함)

세 번째 굵은 녹색 코드 : ExtendedMath.h 실제 내용

마지막 굵은 빨간색 코드 : CPP 파일의 원래 내용


한 번의 #Include는 모든 파일에 영향을 미치기 때문에 정확한 사용법을 숙지해야 합니다.

5. 여러 파일 포함하기의 문제점 해결 - A


두 가지 방법으로 이 문제점을 해결할 수 있습니다. 먼저, 전처리기의 Statement가 포함하는 부분들을 살펴볼 것인데, 이땐 #define과 #infdef를 사용해야 합니다.


#define 문은 TAG란 매크로가 정의되고 설정되었음을 컴파일러에게 알리며, 내용은 #ifndef와 #endif 사이에 정의합니다.


ifndef tag endif 태그[C++ 헤더파일 중복방지] MFC 사용 가능


실제 구현한 SimpleMath.h와 ExtendedMath.h 파일의 수정본은 아래와 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef _SIMPLEMATH_H__
#define _SIMPLEMATH_H__
 
int Add_Numbers(intint);
int Mult_Numbers(intint);
 
int Add_Numbers(int a, int b)
{
    return (a + b);
}
 
int Mult_Numbers(int a, int b)
{
    return (a * b);
}
 
#endif
 
==== 
 
#ifndef _EXTMATH_H_
#define _EXTMATH_H_
 
#include "SimpleMath.h"
 
int Add_three_numbers(intintint);
int Add_three_numbers(int a, int b, int c)
{
    return ( Add_Numbers(a, b) * c );
}
#endif
cs


CppTest.cpp가 ExtendedMath.h 파일을 참조할 때 컴파일러는 ExtendedMath.h 내부에 #Include 된 SimpleMath.h를 생략하여 컴파일이 정상적으로 수행될 것입니다.


6. 여러 파일 포함하기의 문제점 해결 - B


#pragma once를 사용하는 방법은 쉽습니다. #ifndef와 #endif를 사용하지 않아도 됩니다.


1
2
3
4
5
6
7
8
9
#pragma once
#include "SimpleMath.h"
 
int Add_three_numbers(intintint);
 
int Add_three_numbers(int a, int b, int c)
{
    return ( Add_Numbers(a, b) * c );
}
cs


#pragma를 이용하면, 각종 포인터 연산으로 더 짧고 간결한 코딩도 가능합니다. 개발자가 구조체의 형태를 알기에, 1바이트 단위로 간결하게 구조체의 데이터를 조작할 수 있습니다.


헤더 파일의 보호나 네임스페이스 오염을 막으려는 방편보다 더 확장된 개념이겠죠.


[C++구조체] #Pragma Once 사용, 헤더파일 안전하게 사용

댓글