'pragma'에 해당되는 글 1건

  1. 2006.11.15 #pragma once


#pragma once

Development/C / C++ 2006. 11. 15. 14:14

출처 : http://blog.naver.com/topgunmagic

#pragma once

C의 헤더 파일 최상단에서 자주 볼 수 있는 이 코드는 컴파일러에게 이 헤더 파일이 한번만 빌드되도록 알려주는 명령입니다.

왜 넣어야 하냐면, A.h라는 파일이 여러 곳에서 복잡하게 #include 되어 쓰이게 된다면 그때마다 각각 정의가 추가되게 되어 중첩되는 경우가 발생됩니다. 이 경우 중복 정의되었다는 에러가 발생하게 되지요. 즉 같은 내용이 여러번 빌드되게 되는겁니다. 이를 막기위해 #pragma once가 필요합니다. 물론 컴파일시간도 줄여주므로 대부분의 헤더파일에 추가하기를 추천합니다.

#pragma는 C언어에서 컴파일러에 직접 정보를 전하기 위해 사용합니다.

MSDN에서 발췌한 내용입니다.

#pragma once

Specifies that the file will be included (opened) only once by the compiler in a build. This can reduce build times as the compiler will not open and read the file after the first #include of the module.

For example,

// header.h 
#pragma once ....

=================================================================

1.define시에 꼭 정의를 할 필요는 없다.

#define A

#ifdef _A
....(코드)
#endif
라고 사용하는데
컴파일러가 컴파일할때 위 문장을 만나면 _A 가 이전에 정의되어있는지 확인합니다.
#define _A 라는 문장이 이전에 나왔는지 검사한다는 이야기입니다.

확인후 정의되어 있으면 #ifdef 부터 #endif 까지 컴파일을 하죠.
하지만 정의되어있지 않으면 #ifdef 부터 #endif 까지 해석하지않고 건너뜁니다.
마치 /* ... */ 주석으로 막아둔 부분처럼 말입니다.

4)
#ifndef _DEFINES_H_
#define _DEFINES_H_
처럼 만드는 부분은 일반적으로 헤더를 만들때 헤더를 define 문으로 묶어주는데
헤더 마지막에 #endif 가 있을 겁니다.
이렇게 해놓으면
정의된 헤더는 한번만 해석되죠. 컴파일될때 한번만 된다는 말입니다.
처음 #include "헤더" 했을때는 _DEFINES_H_ 란 이름이 한번도 정의도지 않았습니다.
그러니까 소스에 한번 들어갑니다.
들어가니까 _DEFINES_H_ 를 한번 정의해주는군요.
만약 다음에도 똑같이 #include 로 헤더를 집어넣어도 _DEFINES_H_ 가 한번 정의되어
있기때문에 인클루드되지않습니다.
그렇기때문에 중복정의되었다는 오류를 내보내지 않죠.

컴파일시 안전을위해 정의해둔 일종의 보험이죠.

5) 추가내용
#ifndef 는 if not defined 란 말로 정의가 되어있지 않으면~이란 말입니다.

#ifdef 이름 는 #if defined(이름) 과 같은 말이고
#ifndef 이름 은 #if !defined(이름) 과 같은 말입니다.

다음과 같이 사용할 수도 있습니다.

#ifdef ...
<정의되었을경우>
#else
<정의되지 않았을경우>
#endif

#if defined(하나) && defined(둘)
#endif

#if defined(하나) && defined(둘) || defined(셋) ...
#endif

#ifdef 하나
#elif defined(둘)
#elif defined(셋) && !defined(넷)
#else
#endif

마음데로 사용하실수 있습니다.

18-3.pragma 지시자

18-3-가.once

C 언어의 장점 중 하나는 어느 운영체제나 플랫폼으로 쉽게 이식될 수 있는 이식성(Portability)이다. 유닉스에서 작성한 소스를 윈도우즈로 가져와 컴파일하면 똑같은 동작을 하는 실행 파일을 얻을 수 있다. 그러나 이 이식성은 어디까지나 소스 차원에서 이식 가능성을 의미하는 것이지 컴파일된 결과인 실행 파일은 그렇지 않다. C언어는 이식성이 있지만 C언어를 특정 플랫폼에 맞게 컴파일하여 고유의 실행 파일을 만들어 내는 컴파일러는 본질적으로 플랫폼에 종속적이다.

그래서 각 플랫폼에서 실행되는 컴파일러는 플랫폼의 고유한 기능을 수행하기 위한 지원을 해야 한다. 플랫폼별로 구조나 기능이 다르기 때문에 구현도 약간씩 달라질 수 있는데 예를 들어 메모리를 관리하는 방식이나 실행 파일의 특수한 구조로 인한 코드 배치 방법이 플랫폼별로 고유하다. #pragma 지시자는 플랫폼별로 다른 이런 기능에 대한 지시 사항을 컴파일러에게 전달하는 방법이다. #문자로 시작하므로 전처리 명령처럼 보이지만 컴파일러 지시자이다. #pragma 지시자의 기본 형식은 다음과 같다.

#pragma 토큰문자열

#pragma 다음에 지시 사항을 전달하는 토큰 문자열이 오는데 이 토큰의 종류는 컴파일러별로 다르다. 플랫폼에 종속적인 기능에 대한 지시자이므로 #pragma 지시자는 컴파일러에 대해서 종속적일 수밖에 없다. 그래서 특정 플랫폼을 위한 프로그램을 작성할 때만 사용해야 하며 꼭 이식성을 유지하려면 조건부 컴파일 지시자와 함께 사용해야 한다. 컴파일러는 #pragma 다음의 토큰을 인식할 수 없을 경우 단순히 무시해 버리며 컴파일은 계속 수행한다. 다음은 비주얼 C++ 6.0의 pragma 토큰들이다.

alloc_text, auto_inline, bss_seg, check_stack, code_seg, comment, component, conform

const_seg, data_seg, deprecated, function, hdrstop, include_alias, init_seg, inline_depth

inline_recursion, intrinsic, managed, message, once, optimize, pack, pointers_to_members

pop_macro, push_macro, runtime_checks, section, setlocale, unmanaged, vtordisp, warning

종류가 굉장히 많고 이 중 몇 가지는 굉장히 어렵고 복잡한 것도 있다. 우선 가장 이해하기 쉬운 once부터 구경해 보자. 이 지시자를 헤더 파일 선두에 써 두면 컴파일러는 딱 한 번만 헤더 파일을 포함하여 컴파일 시간을 절약한다. 다음과 같은 조건부 컴파일 지시자로 한 번만 포함되도록 하는 것과 효과가 동일하다.

#ifndef _SOME_HEADER_FILE

#define _SOME_HEADER_FILE

// 헤더 파일 내용

#endif // _SOME_HEADER_FILE

같은 헤더 파일을 일부러 두 번 포함하지는 않겠지만 헤더 파일끼리 서로 중첩을 하다 보면 원치 않게 두 번 포함되는 경우도 있다. 헤더 파일에 중복해도 상관없는 선언만 있다면 아무 문제가 없겠지만 중복해서는 안되는 정의가 있는 경우는 이런 식으로 한 번만 포함하도록 해야 한다.

: