전처리기 오퍼레이터 정리

Stringizing Operator (#)
#define stringer( x ) printf( #x “\n” )

int main()
{
    stringer( In quotes in the printf function call\n );
    stringer( “In quotes when printed to the screen”\n );   
    stringer( “This: \”  prints an escaped double quote” );
}

이런식으로 매크로를 사용할 경우 전처리를 거치면
 

int main()
{
   printf( “In quotes in the printf function call\n \n );
   printf( \”In quotes when printed to the screen\”\n \n );
   printf( \”This: \\\” prints an escaped double quote\” \n );
}

이런 코드로 바뀌고

In quotes in the printf function call

“In quotes when printed to the screen”

“This: \” prints an escaped double quotation mark”

결과는 이렇다.

Charizing Operator (#@)

#define makechar(x)  #@x

a = makechar(b);

이렇게 정의하고 사용을 하면

a = ‘b’;

이런 의미가 된다.

Token-Pasting Operator (##)

#define paster( n ) printf( “token” #n ” = %d”, token##n )

int token9 = 9;
paster( 9 );

이렇게 하면

printf( “token” “9” ” = %d”, token9 );

이렇게 바뀌고 결돠적으로

printf( “token9 = %d”, token9 );

이렇게 된다.

정리 참고는 MSDN

정리한 이유.

근래에 코드 정리를 하다가 로그를 남기는 부분을 보게되었다.

#ifdef _DEBUG
  LOG(“블라블라블라”);
#endif

이런식으로 되어 있는데 메크로를 잘 이용하면 저렇게 #ifdef 블럭으로 감싸지 않고도 자동으로 릴리즈바이너리에 포함되지 않도록 할수 있다.

간단하게

#ifdef _DEBUG
  #define LOG(x)    writeLog(x)
#else
  #define LOG(x)
#endif

이렇게 만들수도 있다.
LOG가 메크로고 실제 쓰는 함수는 writeLog일때 릴리즈 모드일때는 아예 writeLog 코드는 사라져 버린다. 하지만 이건 인자가 하나일 경우에만 가능하다. 가변인자(printf같은것)를 사용하는 로그함수일 경우에는 약간더 복잡해 지는데 C99 표준이 지원되는 컴파일러일 경우에는

#ifdef _DEBUG
  #define LOG(fmt, …) writeLog(fmt, __VA_ARGS__)
#else
  #define LOG(fmt, …)
#endif

이렇게 하면 전처리기에서도 가변인자를 처리할수 있고 보는것 처럼 릴리즈 모드에서는 소스에 포함되 않게도 할수 있다.

하지만… 비주얼스튜디오 2003 이하는 __VA_ARGS__ 라는 메크로를 지원하지 않는다.
현재로서는 가장 최신인 2005만 지원하고 있다. 물론 저게 없다고 가변인자를 사용하는 함수들을 메크로로 치환시키지 못하는것은 아니다.

#ifdef _DEBUG
  #define LOG writeLog
#else
  #define LOG
#endif

void writeLog(char* fmt, …);

이렇게 하면 분명 디버그 모드일때는 LOG가 writeLog로 치환되니

LOG(“%s = %d”, szName, value);

이것이

writeLog(“%s = %d”, szName, value);

이렇게 정상치환된다.(물론 당연한 메크로의 기능일 뿐이다.)

하지만 릴리즈 모드에서는?

(“%s = %d”, szName, value);

…이런 코드가 덩그러니 남아버리게 된다.

어떻게 하면 저 덩그러니 남는걸 없앨수 있을까를 고민하다가 어디선가 찾아낸 방법.
바로 Token-Pasting Operator (##) 를 사용하는 방법이다.
(GPG에서 누군가 올렸었던것. 고민중에 돈오하듯이 깨우침.)

#ifdef _DEBUG
  #define LOG writeLog
#else
  #define LOG /##/
#endif

void writeLog(char* fmt, …);

이렇게 해놓으면 릴리즈 모드에서 LOG를 사용한 코드는

//(“%s = %d”, szName, value);

이렇게 치환이 되고 컴파일 과정에서 완벽하게 사라진다.

아싸 조쿠나.