#visualstudio - _noop 키워드

1 minute read

NOOP 혹은 NOP 로 사용하는데, NO OPerator의 줄임말이다. 말 그대로 아무런 연산을 하지 않는 명령어를 뜻한다. 표준이 아니라 VC++ 키워드라는 게 걸리는데, 다른 컴파일러에서 동작하도록 쉽게 수정할 수 있으니 포팅 걱정은 안 하고 VC++에서 편하게 써도 된다. VC++ 이외의 컴파일러에서는 (void(0)) 를 사용하면 된다.

#include <stdio.h>
#if DEBUG
#   define PRINT   printf_s
#else
#   define PRINT   __noop
#endif

int main()
{
    PRINT("\nhello\n");
    return 0;
}

_noop – MSDN에서 예제를 가져왔다. 에이 이걸로 끝? #define PRINT __noop#define PRINT 둘 사이에 다른 게 없다고 생각할지 모르는데, 다르다. 다음 예제를 보자.

#include <stdio.h>
#if DEBUG
#   define PRINT   printf_s
#else
#   define PRINT
#endif

const char* GetOutputString()
{
    printf_s("DEBUG가 0일때 호출되나?\n");
    return "hello";
}

int main()
{
    PRINT("%s\n", GetOutputString());
    return 0;
}

_noop 키워드를 사용하지 않고 비워두었다. GetOutputString()은 호출될까? pre-processor에 의해 PRINT(“%s\n”, GetOutputString());(“%s\n”, GetOutputString()); 으로 변경되고 아무런 동작을 하지 않지만 GetOutputString() 함수를 호출한다. 그래서 위의 소스 코드를 release 빌드해서 실행해 보면 “DEBUG가 0일 때 호출되나?” 문장이 출력된다.

_noop 키워드를 쓰면 __noop(“%s\n”, GetOutputString()); 으로 변경되고 이 문 자체가 실행되지 않고 싹 무시된다.

#include <stdio.h>
#if DEBUG
#   define PRINT(...)   printf_s(__VA_ARGS__)
#else
#   define PRINT(...)
#endif

const char* GetOutputString()
{
    printf_s("DEBUG가 0일때 호출되나?\n");
    return "hello";
}
int main()
{
    PRINT("%s\n", GetOutputString());
    return 0;
}

사실 프로그래머 대부분은 이렇게 인자(argument)까지 define 하는 걸 선호하고 사용한다. 이렇게 작성하면 위와 같은 문제도 없어진다. C99를 지원하지 않아서 Variadic Macros를 사용할 수 없는 컴파일러라면 위와 같이 이름만 define 할지도 모르겠다.

그리고 한 가지 이점이 더 있는데, 비워두지 않고 __noop 키워드를 쓰면 어떤 매크로가 무시되는지 검색하기가 편리하다.

포스팅하는데 발단이 된 게시물 : 자신이 만든 디버그 메시지출력 조절 - GPGstudy