[C] 전처리 지시자

방법이있지·2025년 6월 18일

[정글 4-8주차] C언어

목록 보기
17/26

C언어 코드의 첫 줄을 장식하는 #include <stdio.h>(studio 아님)이 대체 뭔 뜻인지 알아봅시다.

전처리 지시자

  • 소스 코드에서 #으로 시작하는 지시자를 처리하는 과정
  • 대표적으로는 지겹게도 많이 사용한 #include가 있음

#include (파일 포함)

  • 지정한 파일의 내용을 읽어, #include 지시자가 있는 위치에 붙여 놓기
// 파일명 food.h
typedef struct {
    int price;      // 가격
    char name[20];  // 이름
} Food;
// 파일명 1901.c
#include <stdio.h>  // 시스템 헤더 파일의 내용 복사
#include "food.h"   // 직접 작성한 헤더 파일의 내용 복사

int main(void){
    Food f1 = {5000, "김치만두"};
    Food f2 = {6000, "고기만두"};
    printf("%s 가격: %d\n", f1.name, f1.price);
    printf("%s 가격: %d\n", f2.name, f2.price);
    return 0;
}
  • #include <stdio.h>와 같이 화살괄호를 사용하면, 복사할 파일을 컴파일러가 설정한 include 디렉터리에서 먼저 찾음
    • 보통 컴파일러가 제공하는 헤더 파일을 불러올 때 사용
  • #include "food.h"와 같이 쌍따옴표를 사용하면, 복사할 파일을 소스 파일이 저장된 디렉터리에서 먼저 찾음
    • 보통 사용자가 직접 저장한 파일을 불러올 때 사용
    • 경로명을 쌍따옴표 안에 명시하면, 다른 디렉터리의 파일을 불러올 수 있음

#define (매크로 만들기)

매크로 상수

  • #define 매크로명 치환될부분
  • 프로그램에서 사용된 모든 매크로명은, 전처리 과정에서 치환될부분으로 치환됨
    • 이러한 매크로명을 매크로 상수라 부름
  • #define 전처리자에선 세미콜론(;)을 사용하지 않는다는 점에 유의할 것!
#include <stdio.h>
#define WEIGHT 69.5
#define HEIGHT 184
#define NAME "ㅇㅇ"
#define INTRO printf("안녕하세요~\n")

int main(void){
    printf("%s (키 %dcm, 몸무게 %.1lf)\n", NAME, HEIGHT, WEIGHT);
    INTRO;
    return 0;

    // [출력]
    // ㅇㅇ (키 184cm, 몸무게 69.5)
    // 안녕하세요~
}
  • 치환값이 길어 여러 줄에 써야 한다면, \로 연결
#include <stdio.h>
#define CHANHO "제가 LA에 있을때는 말이죠\n정말 \
제가 꿈에 무대인 메이저리그로 진출해서\n가는 식당마다 \
싸인해달라 기자들은 항상 붙어다니며 취재하고\n제가 그 \
머~ 어~ 대통령이 된 기분이였어요"

int main(void){
    printf("%s", CHANHO);
    return 0;

    // [출력]
    // 제가 LA에 있을때는 말이죠
    // 정말 제가 꿈에 무대인 메이저리그로 진출해서
    // 가는 식당마다 싸인해달라 기자들은 항상 붙어다니며 취재하고
    // 제가 그 머~ 어~ 대통령이 된 기분이였어요
}

매크로 함수

  • #define 매크로함수명(인수) (치환될부분)
    • 인수에 따라 치환되는 값이 달라짐
  • 함수 호출보다 상대적으로 실행 속도가 빠름
  • 크기가 작은 함수를 자주 호출하면 도움이 됨
#include <stdio.h>
#define SUM(a, b) ((a) + (b))
#define MUL(a, b) ((a) * (b))

int main(void){
    int a = 50, b = 25;
    int x = 17, y = 24;
    int result;

    printf("a + b = %d\n", SUM(a, b));                  // a + b = 75
    printf("x + y = %d\n", SUM(x, y));                  // x + y = 41
    printf("60 / (3 * 5) = %d\n", 60 / MUL(3, 5));      // 60 / (3 * 5) = 4

    return 0;
}
  • 보통 치환될 부분에는 괄호를 써서 정의
  • 또한, 치환될 부분 내 인수 역시 괄호를 쳐서 정의
  • 괄호가 없으면 아래와 같은 연산 오류가 발생할 수 있음
#define MUL(a, b) a * b
60 / MUL(3, 5);                  // 전처리 전: 우리가 의도한 결과는 60 / (3 * 5) = 4
60 / 3 * 5;                      // 전처리 후: 연산 결과는 60 / 3 = 20, 20 * 5 = 100
#define MUL(a, b) (a * b)
60 / MUL(3, 2 + 8);             // 전처리 전: 우리가 의도한 결과는 60 / (3 * 10) = 2
60 / (3 * 2 + 8);               // 전처리 후: 연산 결과는 60 / 14 = 4

조건부 컴파일 지시자

#include <stdio.h>
#define HEIGHT 184          // 매크로 상수 AGE 정의 -> 15로 치환됨
#define SUNNY            // 매크로 상수 SUNNY 정의 -> 치환될 부분 없음

int main(void){
    printf("당신의 키는 %dcm입니다. ", HEIGHT);
    // 매크로 상수 HEIGHT의 값에 따라 컴파일될 문장이 달라짐
    #if HEIGHT >= 195
        printf("키가 너무 커 티익스프레스를 탈 수 없습니다.\n");
    #elif HEIGHT >= 130
        printf("티익스프레스를 탈 수 있습니다.\n");
    #else
        printf("키가 너무 작아 티익스프레스를 탈 수 없습니다.\n");
    #endif


    #ifdef SUNNY
        // 매크로 상수 SUNNY가 정의되어 있으면
        printf("오늘은 화창해서 티익스프레스가 운영합니다.\n");
    #else
        // 매크로 상수 SUNNY가 정의되어 있지 않으면
        printf("오늘은 비가 와서 티익스프레스가 운영하지 않습니다.\n");
    #endif

    #if (defined(SUNNY) && HEIGHT >= 130 && !(HEIGHT >= 195))
        // &&, ||, ! 등을 사용할 수 있음
        printf("좋아요 티익스프레스를 타러 가요!\n");
    #endif


    // [출력]
    // 당신의 키는 184cm입니다. 티익스프레스를 탈 수 있습니다.
    // 오늘은 화창해서 티익스프레스가 운영합니다.
    // 좋아요 티익스프레스를 타러 가요!
    return 0;
}
  • #if ~ #elif ~ #else ~ #endif 구문을 사용
    • 조건식이 참이면, 대응되는 문장을 컴파일함
    • 컴파일될 문장이 2문장 이상이여도, 중괄호를 사용하지 않음
  • #if defined 매크로명을 사용해, 특정 매크로명이 정의되었는지를 조건문으로 검사 가능
    • #ifdef 매크로명로 줄여서 사용하는 것도 가능
    • 정의되지 않았을 때를 조건문으로 검사하고 싶은 경우, #if !defined 혹은 #ifndef 매크로명을 사용
  • &&, ||, !을 조건부 컴파일 지시자에 사용할 수 있음

연습문제

사칙연산 수식을 입력하면 그 결과를 출력하는 프로그램을 작성합니다. Ctrl+Z를 입력하기 전까지 입출력을 반복합니다. 단, 수식을 입력하는 함수와 사칙연산 함수를 매크로 함수로 작성하세요.

  • scanf는 입력에 실패하면 -1을 반환하므로, -1을 반환하기 전까지 반복문 실행
  • 매크로 함수 정의할 때, 치환할 부분 바깥에 괄호 쳐 주고, 인수에도 괄호 쳐 주는 거 까먹지 않기
#include <stdio.h>
#define PLUS(x, y) ((x) + (y))
#define MINUS(x, y) ((x) - (y))
#define MUL(x, y) ((x) * (y))
#define DIV(x, y) ((x) / (y))
#define INPUT(num1, num2, calc) scanf("%d %c %d", &(num1), &(calc), &(num2))

int main(void){
    int num1, num2, result;
    char calc;

    while (1){
        printf("수식 입력(종료 Ctrl + Z): ");
        if (INPUT(num1, num2, calc) == -1) break;

        switch (calc){
            case '+':
                result = PLUS(num1, num2);
                break;
            case '-':
                result = MINUS(num1, num2);
                break;
            case '*':
                result = MUL(num1, num2);
                break;
            case '/':
                result = DIV(num1, num2);
                break;
        }

        printf("%d %c %d = %d\n", num1, calc, num2, result);
    }

    return 0;

    // [실행결과]
    // 수식 입력(종료 Ctrl + Z): 10 + 20
    // 10 + 20 = 30
    // 수식 입력(종료 Ctrl + Z): 10 - 4
    // 10 - 4 = 6
    // 수식 입력(종료 Ctrl + Z): 10 * 5
    // 10 * 5 = 50
    // 수식 입력(종료 Ctrl + Z): 10 / 4
    // 10 / 4 = 2
    // 수식 입력(종료 Ctrl + Z): ^Z
    // ^Z
    // ^Z

}
profile
뭔가 만드는 걸 좋아하는 개발자 지망생입니다. 프로야구단 LG 트윈스를 응원하고 있습니다.

0개의 댓글