26. 매크로와 전처리기
I. 전처리기에 의한 매크로 처리
-
전처리기에 의한 전처리
- 소스 코드는 컴파일이라는 과정과 링크라는 과정을 거쳐서 실행 파일이 생성된다.
- 컴파일이라는 과정을 구체적으로 세분화 하면 전처리 단계와 컴파일 단계로 나눌 수 있다.
-
#define으로 시작하는 전처리기 지시자
- 문자로 시작하는 문장을 가리켜 전처리기 지시자라한다.
- #include, #define 등등 있다.
-
#define : 단순 치환 적업을 요청할 때 사용되는 지시자 이다.
- #전처리기 지시자 + 매크로 + 대체리스트 (+는 빼고 생각해라) 의 형태로 되어 있으며 매크로를 대체리스트로 대체하라는 뜻이다. 매크로 선언은 문장의 긑을 의미하는 세미콜론을 붙이지 않는다.
- #include <stdio.h>
#define PI 3.1415 - int main()
{
double area;
double radius; - fputs("반지름 : ",stdout);
scanf("%lf",&radius); - area = radius*radius*PI;
printf("넓이는 %f 입니다. \n",area); - return 0;
}
-
위와 같이 PI를 3.1415로 치환을 한다.
- #include <stdio.h>
#define NUM 10 - int main()
{
int arr[NUM] = {1,2,3,};
int i; - for (i =0;i<NUM;i++)
printf("%d",arr[i]); - return 0;
}
- 배열도 가능하다.
- #include <stdio.h>
- #define string "C++"
#define cal (3*4)+(4/2) - #define ONE 1
#define TWO ONE + ONE
#define THREE TWO + ONE - int main()
{
printf("string : %s\n",string);
printf("cal : %d\n",cal);
printf("ONE = %d,TWO = %d,THREE = %d\n",ONE,TWO,THREE); - return 0;
}
- 이미 선언된 매크로를 다른 매크로 선언에서 사용할 수 있다.
- 대체 리스트 영역에는 공백도 존재할 수 있다.
- 매크로에 의한 치환은 문자열 내에서는 이루어지지 않는다.
II. 매크로를 이용한 함수의 구현
-
매크로 함수의 선언
- 매크로에 함수를 선언 하는 것이다. 다음 예제를 보자
- #include <stdio.h>
- #define SQUARE(x) x*x
- int main()
{
int a;
float d; - printf("Input a number(int) : ");
scanf("%d",&a);
printf("Square of %d : %d\n",a,SQUARE(a)); - printf("Input a number(float) : ");
scanf("%f",&d);
printf("Square of %f : %f\n",d,SQUARE(d));
return 0;
}
- 위의 소스 처럼 #define SQUARE(x) x*x 처럼 선언하면 컴파일러가 알아서 바꾸어준다.
-
매크로를 이용한 함수의 정의에 대한 이점
- 첫번째, 매크로 함수는 자료형 독립적이다.
-
두번째, 실행 속도가 향상된다.
- 함수의 크기가 작아야 한다는 점. 함수의 크기가 클수록 그만큼 치환되어 들어가는 코드의 양이 많아지게 된다.
- #include <stdio.h>
- #define SQUARE(x) x*x
int square(int x);
int main()
{
int a;
float d;- 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)) 이렇게 바꾸면 된다.
- #을 이용한 매크로 함수 전달 인자의 문자열화
- #include <stdio.h>
- #define ADD(x,y) printf("x + y = %d",x+y)
- 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"
- #include <stdio.h>
- #define ADD(x,y) printf(#x "+" #y "= %d",x+y)
- int main()
{
ADD(3,4);
return 0;
}
- 위와 같은 식으로 매크로를 바꾸어 주면 된다.
-
##을 이용한 토큰의 결합
-
- 토큰 : 컴파일러가 인식하는 의미를 지니는 문자나 문자열의 최소 단위.
- #include <stdio.h>
- #define CONCAT(a,b) a ## b
- 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])); - return 0;
}
- 실행을 시키면 어떻게 되는 건지 알수 있을 것이다.
III. 이미 정의되어 있는 표준 매크로
표준 매크로 | 의 미 |
---|---|
__FILE__ | 현재 소스 코드의 파일명을 나타내는 문자열 |
__TIME__ |
컴파일 시각을 "시:분:초"의 형태로 나타내는 문자열 |
__DATE__ |
컴파일 날짜를 "년 월 일"의 형태로 나타내는 문자열 |
__LINE__ | 현재 처리중인 소스파일의 행 번호를 나타내는 문자열 |
- #include <stdio.h>
- int main()
{
printf("현재 라인 번호 : %d\n",__LINE__);
printf("파일 이름 : %s\n",__FILE__);
printf("컴파일 시간 : %s\n",__TIME__);
printf("컴파일 날짜 : %s\n",__DATE__);
return 0;
}
이 글은 스프링노트에서 작성되었습니다.
'2. C/C++ > 01. C' 카테고리의 다른 글
25. 메모리 관리와 동적 할당 (0) | 2008.12.07 |
---|---|
24. 파일 입.출력 (0) | 2008.12.07 |
23. 구조체와 사용자 정의 자료형2 (0) | 2008.12.07 |
22. 구조체와 사용자 정의 자료형1 (0) | 2008.12.07 |
21. 문자와 문자열 처리 함수 (0) | 2008.12.07 |