[C언어] 9. 매크로와 선행처리기




제가 책(윤성우의 열혈 C 프로그래밍)을 보다가 까먹었던 부분만 포스팅 하는 것입니다!

순서가 뒤죽박죽이어도 이해해주세요~~!

선행처리



선행처리는 컴파일 이전의 처리를 의미합니다~

소스파일은 선행처리기를 거친 후 컴파일러를 거쳐 오브젝트 파일이 되고,

오브젝트 파일은 링커를 거쳐 실행파일이 됩니다.

선행처리기가 하는 일은 직극히 단순한데,

여러분이 삽입해 놓은 선행처리 명령문대로 소스코드의 일부를 수정(단순 치환)합니다.

예를 들어서, 다음과 같은 선언이 있다고 하면,

#define PI 3.14 //선행처리 명령문

선행처리기는 파일 전체에서 PI를 만나면 3.14로 모두 치환합니다

또 지금까지 선언하였던 #include <stdio.h> 선언도 선행처리 명령문입니다.

의미하는 것은 다음과 같습니다

"stdio.h 파일의 내용을 이곳에 가져다 놓으세요"



대표적인 선행처리 명령문: #define



대표적인 선행처리 명령문은 #define 이 있습니다!

#define PI 3.1415

#define은 지시자, PI는 매크로, 3.1415는 매크로 몸체라고 합니다.

그리고 문장 끝에 세미콜론이 없는 것을 명심하세요!

위의 명령어는 매크로를 매크로 몸체로 치환하라는 뜻입니다.



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


#define SQUARE(X) ((X)*(X))

보통 매크로의 이름은 대문자로 씁니다~

또, 함수를 정의할 때는 괄호를 마구마구쳐야 정상적인 출력 값을 기대할 수 있습니다.



매크로를 두 줄에 걸쳐서 정의하려면 \을 이용합니다.


#define SQUARE(X)	\
		((X)*(X))



또 매크로 정의 시, 먼저 정의된 매크로도 사용이 가능합니다~


#define PI 3.14

#define PRODUCT(X,Y) ((X)*(Y))

#define CIRCLE_AREA(R) (PRODUCT((R),(R))*PI)



그렇다면, 매크로 함수의 장점은 무엇일까요??


매크로 함수는 일반 함수에 비해 실행속도가 빠릅니다.

자료형에 따라서 별도로 함수를 정의하지 않아도 됩니다.



그에 비해 단점은,


정의하기가 까다롭습니다

디버깅하기가 쉽지 않습니다




따라서 보통 매크로 함수는 

작은 크기의 함수

호출의 빈도 수가 높은 함수일 때 주로 정의합니다.



조건부 컴파일을 위한 매크로



조건부 코드 삽입을 위한 지시자에는 #if… #endif가 있습니다

#define ADD 1

#if ADD //ADD가 참이라면

	...
	
#endif



두번째로 #ifdef… #endif 이 있습니다.


#define ADD 1

#ifdef ADD //ADD가 정의되었다면

	...
	
#endif



그리고 헤더파일 중복을 위해 자주 사용하는 #ifndef… #endif가 있습니다.


#define ADD 1

#ifndef ADD //ADD가 정의 되지 않았다면

	...
	
#endif



또한, #if, #ifdef, #ifndef #else도 추가할 수 있습니다.


#define HIT_NUM 7

#ifdef HIT_NUM
	...

#else
	...
	
#endif



마지막으로 #if에만 #elif을 추가할 수 있습니다.


#define HIT_HUM 7

#if HIT_HUM==5
...

#elif HIT_HUM==3
...

#else
...

#endif



매개변수의 결합과 문자열화



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

#define STRING_JOB(A,B) "A의 직업은 B입니다."

위와 같이 선언하면

STRING_JOB(꾸리,프로그래머)라는 문장이

"꾸리의 직업은 프로그래머입니다." 라고 만들어낼 것을 기대하지만,

현실은

"A의 직업은 B입니다." 라고 나옵니다..

문자열 내에서는 매크로의 매개변수 치환이 발생하지 않기 때문입니다.




우리가 원하는 결과가 나오게 하려면 다음과 같이 선언하여야 합니다.

#define STRING_JOB(A,B) #A "의 직업은 " #B "입니다."

#연산자는 매크로의 매개변수에 전달되는 A,B를 문자열로 치환하게 해줍니다.

예를 들어, 다음의 문장을 선언하면,

#define STR(ABC) #ABC

STR(123)은

선행처리기에 의해서 "123"으로 치환됩니다.



그리고 문자열을 나란히 선언하면, 하나의 문자열로 간주가 됩니다.

따라서 다음 표현은 같습니다.


char *str="ABC""DEF";

char *str="ABCDEF";



그리고 매크로의 매개변수를 단순히 결합하고 싶다면 연산자 ##을 사용합니다.


예를들어 다음과 같이 선언되면,

#define CON(UPP,LOW) UPP ## 00 ## LOW

CON(22,77)은 

220077으로 치환이 됩니다.