전처리 지시자

2023. 2. 15. 16:56C언어/기본 개념

728x90

전처리: 컴파일러가 처리하는것이 아닌 전처리기라는 것이 전처리 단계해서 처리하는 것이다.

컴파일러에 소스코드를 넘기기전에 코드를 편집해주고 다듬어주는 과정이다.

 

컴파일 과정

소스파일       >       전처리된 소스파일         >        개체 파일          >         실행파일

                 전처리                                      컴파일                          링크

전처리: 소스파일을 컴파일러가 컴파일하기 좋게끔 다듬는 과정(주석, 전처리 지시문 처리)

전처리 지시자

  1. 다른 파일에 있는 내용을 소스코드로 가져오는 #include
  2. 매크로 상수와 함수를 만드는 #define
  3. 이미 정의된 매크로(__FILE__, __FUNTION__ 등)
  4. 매크로 함수 연산자 #과 ##
  5. 조건부 컴파일 지시자
  6.  #pragma 지시자

1. #include 지시자

#으로 시작하면 전처리 지시자.

지정한 파일의 내용을 읽어 지시자 위치에 붙여 넣는다.

파일명을 <> 또는 " "로 묶는다.

<>와 " " 의 차이점

ex. #include <stdio.h> 경우

시스템 헤더파일을 컴파일러가 설정한 include 디렉터리에서 찾는다.

ex. "student.h"

사용자정의 헤더 파일

소스파일이 저장된 디렉터리에서 먼저 찾고 없다면 include 디렉터리에서 다시 찾아본다.

ex. #include "C:\user\myhdr.h"

직접 경로를 지정도 할 수 있다.

 

전처리가 끝나면 인클루드한 파일의 내용은 복사되어 소스파일에 포함된다.


2. #define 지시자

복잡한 상수나 문장에 대해 매크로명을 정의

#define PI 3.141592                               //상수
#define LIMIT 100.0                               //상수
#define MSG "passed!"                         // 문자열
#define ERR_PRN printf("범위를 벗어났습니다.\n")              //출력문

 

#define SUM(a,b) ((a)+(b))

#define MUL(a,b) ((a)*(b))

인수에 따라 서로 다른 결과값을 갖도록 치환한다.

매크로 함수는 부작용을 줄이기 위해 괄호를 사용.

a = SUM(1,2);

b= MUL(3, 5);

printf("a 출력 값 : %d",a);

printf("b 출력 값 : %d",b);

a 출력 값 : 3

b 출력 값 : 15


3. 이미 정의된 매크로

정의가 되어 있기 때문에 취소하거나 수정이 안 된다.

정의된 매크로 기능
__FILE__ 전체 디렉터리 경로를 포함한 파일명
__FUNTION__ 매크로명이 사용된 함수 이름
__LINE__ 매크로명이 사용된 행 번호
__DATE__ 컴파일을 시작한 날짜
__TIME__ 컴파일을 시작한 시간

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
void func(void);
int main(void
{
    printf("컴파일 날짜와 시간 : %s, %s\n\n", __DATE__, __TIME__);
    printf("파일명 : %s\n", __FILE__);
    printf("함수명 : %s\n", __FUNCTION__);
    printf("행번호: %d\n////////////////////////////\n", __LINE__);
#line 100 "macro.c"
   func(); //100행
 
 
    return 0;
}
void func(void)
{
 
    printf("컴파일 날짜와 시간 : %s, %s\n\n", __DATE__, __TIME__);
    printf("파일명 : %s\n", __FILE__);
    printf("함수명 : %s\n", __FUNCTION__);
    printf("행번호: %d\n", __LINE__);
}
cs
컴파일 날짜와 시간 : Feb 16 2023, 10:44:12

파일명 : C:\stu.c
함수명 : main
행번호: 8
////////////////////////////
컴파일 날짜와 시간 : Feb 16 2023, 10:44:12

파일명 : macro.c
함수명 : func
행번호: 111

9행부터 코드로 인해 10행부터 100, 101, 102... 로 행 번호가 바뀐다. 그리고 파일명도 "macri.c"로 바꾸었다.


4. 매크로 함수 연산자 #과 ##

#은 매크로 함수의 인수를 문자열로 치환한다.

##은 두 인수를 붙여서 치환한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#define PRINT_EXPR(x) printf(#x " = %d\n", x)
#define NAME_CAT(x,y) (x ## y)
 
int main(void
{
    int a1, a2;
    NAME_CAT(a, 1= 10// a와 1을 합쳐서 a1 변수를 만든다.
    NAME_CAT(a,2= 20;
    PRINT_EXPR(a1 + a2); // #x로인해 "a1 + a2" 문자로 치환 된다
    PRINT_EXPR(a2 - a1);
    return 0;
}
cs

8, 9행을 보면 a1, a2라는 변수를 만들기 위해서  a에다가 숫자를 이어 붙여주었다.

10, 11행은 2행에 정의한 방식대로 하면 인수로 넣은 식이 문자열로 바뀌면서 식과 값을 출력할 수 있게 된다.

a1 + a2 = 30
a2 - a1 = 10

5.조건부 컴파일 지시자

조건에 따라 소스코드를 선택적으로 컴파일

#if ~ #elif ~ #else ~ #endif
#if 조건식
        컴파일 문장
#endif
#if defined BIT16     //#ifdef BIT16 과 동일하다.
       컴파일 문장
#endif
#if (defined (BIT16) && (VER >= 6)) //VER : 버전
    컴파일 할 문장
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#define VER 7
#define BIT16 // 치환 부분 X
 
int main(void
{
    int max;
#if VER >= 6
    printf("버전 %d입니다.\n", VER);
#endif
 
#ifdef BIT16
    max = 32767;
#else
    max = 2165468515;
#endif
    printf("max = %d", max);
 
    return 0;
}
cs

 

#undef //매크로명 정의 취소
#error // 메시지를 출력하고 컴파일 중단
        ex.#error 컴파일러 버전은 6.0이상이어야합니다.

6.pragma 지시자

컴파일러의 컴파일 방법을 제어

ex. #pragma pack(1)

#pragma warning(disable:4996)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#pragma pack(push, 1//바이트 얼라인먼트를 1로 // 패딩 바이트 포함하지 않는다.
typedef struct
{
    char ch;
    int in;
}Sample1;
#pragma pack(pop// 바꾸기 전에 바이트 얼라인먼트 적용
typedef struct
{
    char ch;
    int in;
}Sample2;
 
int main(void
{
    printf("Sample1 구조체의 크기 : %d바이트\n"sizeof(Sample1));
    printf("Sample2 구조체의 크기 : %d바이트\n"sizeof(Sample2));
 
    return 0;
}
cs

2행 push는 바이트 얼라인먼트를 바꿀 때 규칙을 기억한다는 뜻이다.

Sample2는 가장 큰 크기(int형)에 맞춰서 공간을 확보하기 때문에 8바이트가 된다.

728x90

'C언어 > 기본 개념' 카테고리의 다른 글

분할 컴파일  (0) 2023.02.23
파일 개방 및 입출력  (0) 2023.02.14
구조체 활용, 공동체, 열거형  (0) 2023.02.10
구조체  (0) 2023.02.09
동적 할당 저장 공간의 활용  (0) 2023.02.09