BLOG ARTICLE Preprocessor | 1 ARTICLE FOUND

  1. 2007.01.14 C/C++ 프리프로세서 명령

 

C++ 프리프로세서 명령

16.1 서론

16.2 C++ 프리프로세서

16.3 파일의 include

16.4 단순한 문자열 치환

16.5 인수 없는 매크로

16.6 인수 있는 매크로

16.7 매크로 정의 해체

16.8 조건 컴파일러

16.9 #pragma

16.10 정리


 ◈ 16.2 C++프리프로세서

-C++프리프로세서 명령의 규칙은 C와 동일

-프리프로세서는 컴파일러에 넘겨주시 전에 프로그램의 소스 코드를 처리하는 프로그램이다.

-프리프로세서 명령은 기호 #이 앞에 놓여지고 프리프로세서 제어행이라고 부름.

-제어행의 내용에 따라 하나 또는 그 이상의 기능을 실행함.


■파일의 include

-다음이 있으면 파일이 include됨

 

 

 

 

#include

 

 

 


■문자열의 치환, 매크로 전개나 정의해제

-문자열의 치환, 매크로 전개나 정의해제 기능은, 다음의 명령으로 구현됨

 

 

 

 

#define 

#undef

 

 

 



■조건 컴파일의 명령

-조건 컴파일은, 다음의 제어행을 조합해서 구현됨

 

 

 

 

#if 

#else 

#endif 

#if 

#elif 

#endif 

#ifdef 

#endif 

#ifndef 

#endif

 

 

 


■디버그 작업의 보조

-다음의 제어행은 디버그를 지원함.

 

 

 

 

#pragma

 

 

 



 ◈ 16.3 파일의 include(1)


 

 

 

 

// test16_1.cpp//오류발생

//#include <iostream.h>

//#include <stdio.h>

void main(void)

{ 

  cout <<"Hi there ! \n";

        printf  ( "Hi there again ! \n");

}

 

 

 

-오류 매시지

 

 

 

 

error C2065: 'cout' : undeclared identifier

error C2297: '<<' : illegal, right operand has type 'char [13]'

error C2065: 'printf' : undeclared identifier

 

 

 


 ◈ 16.3 파일의 include(2)

 

 

 

 

// test16_2.cpp

#include <iostream.h>

#include <stdio.h>

void main(void)

{ 

  cout <<"Hi there ! \n";

        printf  ( "Hi there again ! \n");

}

 

 

 

-실행 결과

 

 

 

 

Hi there !

Hi there again !

 

 

 


-#include 명령은 컴파일 시에 명령 뒤에 있는 파일명의 모든 내용을 include함.

-헤더 파일 iostream.h는 cout의 정의를, stdio.h는 printf()의 정의를 포함


-#include 명령의 3가지 형식

■#include <filename>

 ∙<>괄호 안의 파일명은 컴파일러에게 현재의 작업 디렉토리 이외의 미리 준비된 디렉토리(표준 디렉토리)의 리스트로부터 그 파일을 찾도록 지시


■#include “filename”

∙컴파일러에게 현재의 작업 디렉토리 내에서 그 파일을 찾도록 지시


■#include “c:\wkspace\kdhong\"filename”

∙컴파일러에게 지정된 경로 내에서 그 파일을 찾도록 지시, 그 디렉토리에서 발견되지 않으면 표준 디렉토리를 찾음.

 

 

 

 

// test_16.3 cpp

#include <iostream.h>            // cout 에 필요

#include <stdio.h>              // printf()에 필요

#include "D:\Lecture2K-2\C++\nykwak.h"

void main(void)

{ 

        cout <<"Hi there ! \n";

        printf  ( "Hi there again ! \n");

        cout <<"a from nykwak.h is " <<a <<"\n";

}

 

 

 

-가령, D:\Lecture2K-2\C++\nykwak.h에 int a = 5;라는 선언문이 삽입되어 있을 경우, 실행 결과는, 다음과 같다.

 

 

 

 

Hi there !

Hi there again !

a from nykwak.h is 5

 

 

 


 ◈ 16.3 파일의 include(3)

 

 

 

 

// test_16.4 cpp//오류발생

#include <iostream.h>            // cout 에 필요

#include <stdio.h>              // printf()에 필요

#include "D:\Lecture2K-2\C++\kdhong.h"

void main(void)

{ 

        cout <<"Hi there ! \n";

        printf  ( "Hi there again ! \n");

        cout <<"a from kdhong.h is " <<a <<"\n";

}

 

 

 

-가령, D:\Lecture2K-2\C++\kdhong.h에

int a = 5

라는 선언문이 삽입되어 있을 경우, 메러 메시지는, 다음과 같다.

 

 

 

 

error C2144: syntax error : missing ';' before type 'void'

fatal error C1004: unexpected end of file found

 

 

 


 ◈ 16.4 단순한 문자열 치환

-일반적으로, #define 제어행을 사용할 때, 대문자를 사용.(그 이유는 프로그램 중에서 #define되는 변수를 쉽게 확인할 수 있기 때문.)

 

 

 

 

// test16_5.cpp//문자열 치환

#include <iostream.h>

#define HELLO "Hi there ! \n"

void main(void)

{ 

        cout <<HELLO ;

} 

 

 

 

-실행 결과

 

 

 

 

Hi there !

 

 

 


 ◈ 16.5 인수 없는 매크로

 

 

 

 

// test16_6.cpp//인수 없는 매크로

#include <iostream.h>         // I/O에 필요

#define SQUARE_TWO 2*2

void main(void)

{ 

        int a;

        a = SQUARE_TWO;

        cout <<"a is " <<a <<"\n";

}

 

 

 

-실행 결과

 

 

 

 

a is 4

 

 

 


-다음 제어행 중,

 

 

 

 

#define SQUARE_TWO 2*2

 

 

 

#define는 제어행으로, SQUARE_TWO는 매크로 템플리트이고, 2*2는 매크로 전개임.

 ◈ 16.6 인수 있는 매크로(1)

 

 

 

 

//test16_7.cpp 

#include <iostream.h>

#define ADD(X) (X+X)

void main(void)

{ 

        int b;

        b = ADD(4);

        cout <<"b is " <<b <<"\n";

}

 

 

 

-실행 결과

 

 

 

 

b is 8

 

 

 



 ◈ 16.6 인수 있는 매크로(2)

 

 

 

 

//test16_8.cpp//오류발생 

#include <iostream.h>

#define ADD (X) (X+X)

void main(void)

{ 

        int b;

        b = ADD(4);

        cout <<"b is " <<b <<"\n";

}

 

 

 

-오류 메시지

 

 

 

 

error C2065: 'X' : undeclared identifier

 

 

 



 ◈ 16.6 인수 있는 매크로(3)

 

 

 

 

//test16_9.cpp//오류발생 

#include <iostream.h>

//매크로명과 파라미터 사이의 괄호가 없는 것에 주의

#define ADD(X) X+X

void main(void)

{ 

        int b;

        b = ADD(4)*5;

        cout <<"b is " <<b <<"\n";

}

 

 

 

-실행 결과

 

 

 

 

b is 24

 

 

 


-test16_9.cpp의 동작 설명

 

 

 

 

 b = ADD(4)*5;

 

 

 

 

 

 

 

 b = 4 + 4 * 5;

 

 

 

와 같이 전개됨.

즉, 곱셈은 덧셈보다 연산우선순위가 빠르기 때문에 다음과 같이 계산됨

 

 

 

 

 b = 4 + (4 * 5);

 

 

 

그러나, 기대했던 것은 다음과 같은 것임.

 

 

 

 

 b = (4 + 4) * 5;

 

 

 

(따라서, 괄호를 생략해서는 안됨)


 ◈ 16.7 매크로 정의 해제

-이미 정의된 (#define) 매크로는 다음과 같은 제어행으로 정의를 해제할 수 있음.


 

 

 

 

#undef

 

 

 


 

 

 

 

// test16_10.cpp//오류발생

#include <iostream.h>

#define FOUR 4

void main(void)

{ 

        int a = FOUR;

        cout <<"a is " <<a <<"\n";

        #undef FOUR

      int b = FOUR;

        cout <<"b is " <<b <<"\n";

} 

 

 

 

-오류 메시지

 

 

 

 

error C2065: 'FOUR' : undeclared identifier

 

 

 


-메크로를 해제하는 이유는, 매크로 명을 필요로 하는 코드 부분만으로 유효 범위를 한정하기 위함.

 ◈ 16.8 조건 컴파일러

-조건 컴파일러는 소스 코드 중의 다음 키워드가 발견되면 수행됨.

 

 

 

 

#if - #else - #endif

#if - #elif  - #endif

#ifdef - #endif

#ifndef - #endif

 

 

 



16.8.1 #if - #else - #endif(1)

-키워드 #if에는 상수식, 코드블록이 이어지고, 그 뒤에 키워드 #endif가 놓여짐.

 

 

 

 

// test16_11a .cpp

#include <iostream.h>         // I/O 에 필요

#define FIVE 5

#define ZERO 0

void main(void)

{ 

       

              #if (FIVE)

                cout <<"FIVE is TRUE, i.e. non-zero \n";

        #else

                cout <<"FIVE is FALSE, i.e. zero \n";

        #endif

        #if (ZERO)

                cout <<"ZERO is TRUE, i.e. non-zero \n";

        #else

                cout <<"ZERO is FALSE, i.e. zero \n";

        #endif

        cout <<"This code is outside the blocks \n";

}

 

 

 

-실행 결과

 

 

 

 

FIVE is TRUE, i.e. non-zero

ZERO is FALSE, i.e. zero

This code is outside the blocks

 

 

 

16.8.1 #if - #else - #endif(2)

 

 

 

 

// test16_11.cpp//MS Visual C++의 경우, 실행되지만 오동작

#include <iostream.h>

void main(void)

{ 

        const int a = 5;

        const int b = 0;

        #if (a)

                cout <<"a is TRUE, i.e. non-zero \n";

        #else

                cout <<"a is FALSE, i.e. zero \n";

        #endif

        #if (b)

                cout <<"b is TRUE, i.e. non-zero \n";

        #else

                cout <<"b is FALSE, i.e. zero \n";

        #endif

       

        cout <<"This code is outside the blocks \n";

}

 

 

 

-실행 결과

 

 

 

 

a is FALSE, i.e. zero

b is FALSE, i.e. zero

This code is outside the blocks

 

 

 



16.8.1 #if - #else - #endif(3)

 

 

 

 

// test16_12.cpp//MS Visual C++의 경우, 실행되지만 오동작

#include <iostream.h>

void main(void)

{ 

        int a = 5;//a와 b는 변수로서 선언되고 있다.

        int b = 0;

        #if (a)

                cout <<"a is TRUE, i.e. non-zero \n";

        #else

                cout <<"a is FALSE, i.e. zero \n";

        #endif

        #if (b)

                cout <<"b is TRUE, i.e. non-zero \n";

        #else

                cout <<"b is FALSE, i.e. zero \n";

        #endif

       

        cout <<"This code is outside the blocks \n";

}

 

 

 

-실행 결과

 

 

 

 

a is FALSE, i.e. zero

b is FALSE, i.e. zero

This code is outside the blocks

 

 

 



16.8.1 #if - #else - #endif(4)


#if-#else-#endif와 정규 if-else-endif 제어 구조의 차이는, 전자에서는 case 평가를 프로그램이 컴파일되기 이전에 한다는 점이다. 테스트 조건 안에 변수를 두어서는 안된다. 왜냐하면, 변수의 값은 실행중에 변할 수도 있기 때문.

16.8.2 #if - #elif - #endif

#if-#elif-#endif는 #if-#else-#endif와 유사

 

 

 

 

// test16_11b.cpp

#include <iostream.h>         // I/O 에 필요

#define FIVE 5

#define ZERO 0

void main(void)

{ 

       

          #if (FIVE)

                cout <<"FIVE is TRUE, i.e. non-zero \n";

        #elif

                cout <<"FIVE is FALSE, i.e. zero \n";

        #endif

        #if (ZERO)

                cout <<"ZERO is TRUE, i.e. non-zero \n";

        #elif(ZERO)

                cout <<"ZERO is FALSE, i.e. zero \n";

        #endif

       

        cout <<"This code is outside the blocks \n";

}

 

 

 


-실행 결과

 

 

 

 

FIVE is TRUE, i.e. non-zero

This code is outside the blocks

 

 

 


16.8.3 #ifdef-#endif

-2개의 제어행 사이의 코드 블록은, 명령의 뒤에 있는 매크로명이 그 앞에 정의되어 있을 때에만 컴파일됨.

 

 

 

 

// test16_14.cpp

#include <iostream.h>

//#define COMPILE

void main(void)

{ 

        #ifdef COMPILE

                cout <<"This code will be compiled \n";

        #endif

} 

 

 

 


-실행 결과

 

 

 

 

 

 

 

 


16.8.4 #ifndef-#endif

-#indef-#endif문의 반대로, 제어행 사이 코드블록은, 매크로 명이 정의되어 있지 않을 때만 컴파일됨.

 

 

 

 

// test16_14.cpp

#include <iostream.h>

#define COMPILE

void main(void)

{ 

        #ifndef COMPILE

                cout <<"This code will be compiled \n";

        #endif

} 

 

 

 


-실행 결과

 

 

 

 

 

 

 

 


 ◈ 16.#pragma

-이 제어행은 컴파일러에 여러 가지 지령을 줄 수 있다. 특수한 지령은 처리계의 독자적인 지령이다.


MSDNdpt의 progma에 대한 설명

Each implementation of C and C++ supports some features unique to its host machine or operating system. Some programs, for instance, need to exercise precise control over the memory areas where data is placed or to control the way certain functions receive parameters. The #pragma directives offer a way for each compiler to offer machine- and operating-system-specific features while retaining overall compatibility with the C and C++ languages. Pragmas are machine- or operating-system-specific by definition, and are usually different for every compiler.


Syntax


#pragma token-string


The token-string is a series of characters that gives a specific compiler instruction and arguments, if any. The number sign (#) must be the first non-white-space character on the line containing the pragma; white-space characters can separate the number sign and the word pragma. Following #pragma, write any text that the translator can parse as preprocessing tokens. The argument to #pragma is subject to macro expansion.


If the compiler finds a pragma it does not recognize, it issues a warning, but compilation continues.


Pragmas can be used in conditional statements, to provide new preprocessor functionality, or to provide implementation-defined information to the compiler. The C and C++ compilers recognize the following pragmas:


alloc_text comment init_seg1 optimize

auto_inline component inline_depth pack

bss_seg data_seg inline_recursion pointers_to_members1

check_stack function intrinsic setlocale

code_seg hdrstop message vtordisp1

const_seg include_alias once warning

AND