C언어 선행처리기 매크로 정의

    2018-02-06 16:54:57 작성

    #define : 소스코드에 나오는 매크로 이름을 지정한 코드로 치환합니다.

    매크로 상수

    #define MAX 100

    #define 정의에서 MAX는 매크로이름이고 100은 매크로의 몸체이며 다음과 같은 의미를 갖습니다.
    "이후 등장하는 MAX 를 매크로몸체 100으로 치환하라."
    일반적으로 매크로이름은 모두 대문자로 작성하고, 두단어를 연결시 _(언더바)를 사용하여 연결합니다.(상수이름 선언과 같음)

    #include <stdio.h>
    
    #define LENGTH 20
    #define SITE_URL "http://ezcode.kr"
    #define PRINT_ADDR puts("주소 : 서울시 도봉구 방학동")
    
    int main(void) {
        double arr[LENGTH];
        printf("arr의 요소 개수 : %d\n", sizeof(arr) / sizeof(arr[0]));
        printf("사이트 URL : %s\n", SITE_URL);
        PRINT_ADDR;
        return 0;
    }

    #define 으로 매크로상수를 3개의 매크로상수를 정의 하였습니다.
    main 함수에서 사용되는 매크로상수는 컴파일단계에서 단순 치환되어집니다.

    이렇게 매크로로 정의하게 되면 그 값을 바꿀수 없기 때문에 상수와 같은 성격을 갖기 때문에 매크로상수라고 합니다.


    매크로 함수

    매크로는 매개변수가 존재하는 형태로도 정의할 수 있습니다.

    #define SQUARE(x) x*x

    위의 코드와 같이 매크로 이름이 함수호출과 같은 형태를 갖는 매크로 정의하면 x는 함수의 매개변수처럼 전달됩니다.
    SQUARE(x)와 같은 형식을 만나면 x*x로 치환합니다.

    #include <stdio.h>
    
    #define SQUARE(x) x*x
    
    int main(void) {
        int a = 20;
        printf("SQUARE(a) : %d\n", SQUARE(a));
        printf("SQUARE(2.5) : %1.2f\n", SQUARE(2.5));
        printf("SQUARE(2+3) : %d\n", SQUARE(2+3)); //잘못된 매크로 정의 결과
        return 0;
    }


    SQUARE(a), SQUARE(2.5) 각각 예상된 결과가 나옵니다.
    SQUARE(2+3) 의 경우 2+3 = 5이고 5*5는 25가 될것이라 예상되지만 결과는 11입니다.
    SQUARE(2+3) 은 매크로 치환시 2+3*2+3으로 치환되며 연산자 우선순위가 *가 높기 때문에 2+6+3 = 11되는 결과가 됩니다.
    그렇다면 SQUARE(2+3)이 25라는 결과값을 갖게 하려면 다음과 같이 ()로 묶어주면 됩니다.

    #define SQUARE(x) ((x)*(x))

    위의 식으로 SQUARE(2+3)이 치환되면 ((2+3)*(2+3))​이 되므로 결과는 25가 됩니다.
    이렇듯 매크로 함수를 정의할 때에는 연산자 우선순위를 고려하여 매크로를 정의 하여야 합니다.


    매크로를 여러줄에 걸쳐서 정의

    선행 처리기 규칙에는 한 줄에 하나의 명령문만 작성하게 되어있습니다.
    매크로 작성시 길이가 길어져 코드의 가독성을 높이기 위해 여러줄에 걸쳐서 매크로를 정의하려면 \를 이용하여 줄이 바뀌었음을 명시해야 합니다.

    #define SQUARE(x) \
        (x)*(x)


    매크로 정의시 먼저 정의된 매크로 사용 가능

    #include <stdio.h>
    
    #define PI 3.1415
    #define SQUARE(x) ((x)*(x))
    #define CIRCLE_AREA(r) ((SQUARE(r))*PI)
    
    int main(void) {
        double radius = 3.6;
        printf("반지름 %g인 원의 넓이는 : %g\n", radius, CIRCLE_AREA(radius));
        return 0;
    }

    매크로 함수의 장ㆍ단점
    장점 매크로 함수는 일반함수에 비해 실행 속도가 빠릅니다.
    자료형에 따라서 별도의 함수를 정의하지 않아도 됩니다.
    단점 복잡한 함수에 대해 정의하기가 까다롭습니다.
    디버깅하기가 쉽지 않습니다.

    크기가 작은 함수나 호출빈도수가 높은 함수를 매크로 함수로 정의하여 사용하는 것이 좋습니다.


    문자열 결합 # 연산자

    문자열내에서는 매크로의 치환이 발생하지 않습니다

    #define STR_COLOR(F, C) "F의 색상은 C색입니다."
    STR_COLOR(사과, 빨간)
    <> 위와 같을때 2행에서 "사과의 색상은 빨간색입니다."라는 문자열을 만들어낼 것이라고 기대하지만
    결과는 "F의 색상은 C색입니다." 와 같이 F와 C가 치환되지 않습니다.

    이렇게 문자열을 결합해야 할때는 다음과 같이 #을 이용해 매크로를 정의하여야 합니다.

    #include <stdio.h>
    
    #define STR_COLOR(F, C) #F "의 색상은 " #C "색입니다."
    
    int main(void) {
    	printf("%s\n", STR_COLOR(사과, 빨간));
    	printf("%s\n", STR_COLOR(바나나, 노란));
    	return 0;
    }


    단순하게 결합 ## 연산자

    년 월 일을 조합하는 매크로 함수를 정의하고자 하며 그 호출 형태는 다음과 같습니다.

    BIRTH(1976, 05, 29)

    위 코드의 결과값이 '19760529' 와 같이 나오게 하려면

    #define BIRTH(Y,M,D) ((Y)*10000+ (M)*100 +(D))

    이렇게 자리수를 계산하여 매크로를 정의하여야 합니다.
    하지만 단순하게 결합만할때는 다음과 같이 정의할 수 있습니다.

    #define BIRTH(Y,M,D) Y ## M ## D

    위와 같이 정의 하면 무엇이 전달되든지 단순히 연결하여 하나의 값을 얻을수 있습니다.


    연습문제

    1. 화씨를 섭씨로 바꾸는 매크로함수를 정의 합니다.
    2. 섭씨를 화씨로 바꾸는 매크로함수를 정의합니다.
    사용자로부터 섭씨 또는 화씨를 입력받아 변환하여 출력하는 프로그램을 작성하세요.
    화씨 > 섭씨 공식 : (화씨 - 32) × (5 ÷ 9)
    섭씨 > 화씨 공식 : (섭씨 × (9 ÷​5)) + 32