26. 매크로와 전처리기

I. 전처리기에 의한 매크로 처리

  • 전처리기에 의한 전처리

    • 소스 코드는 컴파일이라는 과정과 링크라는 과정을 거쳐서 실행 파일이 생성된다.
    • 컴파일이라는 과정을 구체적으로 세분화 하면 전처리 단계와 컴파일 단계로 나눌 수 있다.

 

  • #define으로 시작하는 전처리기 지시자

    •  문자로 시작하는 문장을 가리켜 전처리기 지시자라한다.
    • #include, #define 등등 있다.
    • #define : 단순 치환 적업을 요청할 때 사용되는 지시자 이다.

      • #전처리기 지시자 + 매크로 + 대체리스트 (+는 빼고 생각해라) 의 형태로 되어 있으며 매크로를 대체리스트로 대체하라는 뜻이다. 매크로 선언은 문장의 긑을 의미하는  세미콜론을 붙이지 않는다.
  1.  #include <stdio.h>
    #define PI 3.1415
  2. int main()
    {
     double area;
     double radius;
  3.  fputs("반지름 : ",stdout);
     scanf("%lf",&radius);
  4.  area = radius*radius*PI;
     printf("넓이는 %f 입니다. \n",area);
  5.  return 0;
    }
  • 위와 같이 PI를 3.1415로 치환을 한다.

     

  1. #include <stdio.h>
    #define NUM 10
  2. int main()
    {
     int arr[NUM] = {1,2,3,};
     int i;
  3.  for (i =0;i<NUM;i++)
      printf("%d",arr[i]);
  4.  return 0;
    }
  • 배열도 가능하다.
  1.  #include <stdio.h>
  2. #define string "C++"
    #define cal (3*4)+(4/2)
  3. #define ONE 1
    #define TWO ONE + ONE
    #define THREE TWO + ONE
  4. int main()
    {
     printf("string : %s\n",string);
     printf("cal : %d\n",cal);
     printf("ONE = %d,TWO = %d,THREE = %d\n",ONE,TWO,THREE);
  5.  return 0;
    }
  • 이미 선언된 매크로를 다른 매크로 선언에서 사용할 수 있다.
  • 대체 리스트 영역에는 공백도 존재할 수 있다.
  • 매크로에 의한 치환은 문자열 내에서는 이루어지지 않는다.

 

II. 매크로를 이용한 함수의 구현

  • 매크로 함수의 선언

    • 매크로에 함수를 선언 하는 것이다. 다음 예제를 보자
  1.  #include <stdio.h>
  2. #define SQUARE(x) x*x
  3. int main()
    {
     int a;
     float d;
  4.  printf("Input a number(int) : ");
     scanf("%d",&a);
     printf("Square of %d : %d\n",a,SQUARE(a));
  5.  printf("Input a number(float) : ");
     scanf("%f",&d);
     printf("Square of %f : %f\n",d,SQUARE(d));
     return 0;
    }
  • 위의 소스 처럼 #define SQUARE(x) x*x 처럼 선언하면 컴파일러가 알아서 바꾸어준다.
  • 매크로를 이용한 함수의 정의에 대한 이점

    • 첫번째, 매크로 함수는 자료형 독립적이다.
    • 두번째, 실행 속도가 향상된다.

      • 함수의 크기가 작아야 한다는 점. 함수의 크기가 클수록 그만큼 치환되어 들어가는 코드의 양이 많아지게 된다.
  1.  #include <stdio.h>
  2. #define SQUARE(x) x*x
    int square(int x);

  3. int main()
    {
     int a;
     float d;
  4.  printf("Input a number(int) : ");
     scanf("%d",&a);
     printf("Square of %d : %d\n",a,SQUARE(a+3));
     printf("Square of %d : %d\n",a,square(a+3));
     return 0;
    }
    int square(int x)
    {
     return x*x;
    }
  • 위의 소스를 보면 (a+3)(a+3) 대한 값을 구하려고 하는 소스인데 실행을 해보면 매크로 함수 호출 결과만 이상하게 나온다.

    • 이유는 우리가 의도한 (a+3)(a+3) 이렇게 치환되는 것이 아니라 a+3*a+3 이렇게 바뀌어 버린다.
    • #define SQUARE(x) x*x 를 #define SQUARE(x) ((x)*(x)) 이렇게 바꾸면 된다.

 

  • #을 이용한 매크로 함수 전달 인자의 문자열화
  1. #include <stdio.h>
  2. #define ADD(x,y) printf("x + y = %d",x+y)
  3. int main()
    {
     ADD(3,4);
     return 0;
    }
  • 위의 소스는 3 + 4 = 7 이런식으로 출력하려는 의도로 만든 것이다.

    • 하지만 앞에서 매크로에 의한 치환은 문자열 내에서는 이루어 지지 않는다고 했었다. 그럼 어찌 해야할까?
    • 해결을 위한 특징 1 : C 언어는 문자열 상수를 이어서 선언 할 수 있다.

      • char* str = "Hello" "world"는 char* str = "Helloworld" 와 같다.
    • 해결을 위한 특징 2 : #을 통한 매크로 전달 인자의 문자열화

      • #define FUN1(x) x 이렇게 되어있다면 FUN1(10) -> 10
      • #define FUN2(x) #x 이렇게 되어있다면 FUN2(10) -> "10"
  1. #include <stdio.h>
  2. #define ADD(x,y) printf(#x "+" #y "= %d",x+y)
  3. int main()
    {
     ADD(3,4);
     return 0;
    }
  •  위와 같은 식으로 매크로를 바꾸어 주면 된다.

 

  • ##을 이용한 토큰의 결합

    • 토큰 : 컴파일러가 인식하는 의미를 지니는 문자나 문자열의 최소 단위.
  1.  #include <stdio.h>
  2. #define CONCAT(a,b) a ## b
  3. int main()
    {
     int arr[2] = {100,200};
     
     printf("%d\n",CONCAT(2,4));
     printf("%s\n",CONCAT("Good","Morning?"));
     printf("%d %d\n",CONCAT(arr,[0]),CONCAT(arr,[1]));
  4.  return 0;
    }
  • 실행을 시키면 어떻게 되는 건지 알수 있을 것이다.

 

III. 이미 정의되어 있는 표준 매크로

 

표준 매크로 의   미
 __FILE__ 현재 소스 코드의 파일명을 나타내는 문자열
 __TIME__

 컴파일 시각을 "시:분:초"의 형태로 나타내는 문자열

 __DATE__

 컴파일 날짜를 "년 월 일"의 형태로 나타내는 문자열

 __LINE__  현재 처리중인 소스파일의 행 번호를 나타내는 문자열
  1.  #include <stdio.h>
  2. int main()
    {
     printf("현재 라인 번호 : %d\n",__LINE__);
     printf("파일 이름 : %s\n",__FILE__);
     printf("컴파일 시간 : %s\n",__TIME__);
     printf("컴파일 날짜 : %s\n",__DATE__);
     return 0;
    }

이 글은 스프링노트에서 작성되었습니다.

Posted by kid1412
,