[macros] 컴파일 타임에 #define의 값을 어떻게 표시합니까?

내 코드가 사용하고 있다고 생각하는 Boost 버전을 파악하려고합니다. 다음과 같이하고 싶습니다.

#error BOOST_VERSION

그러나 전처리 기는 BOOST_VERSION을 확장하지 않습니다.

나는 프로그램에서 런타임에 그것을 인쇄 할 수 있다는 것을 알고 있고, 답을 찾기 위해 전 처리기의 출력을 볼 수 있다는 것을 알고 있습니다. 컴파일하는 동안 이것을하는 방법이 유용 할 수 있다고 생각합니다.



답변

이것은 원래 쿼리 이후 오랜 시간이라는 것을 알고 있지만 여전히 유용 할 수 있습니다.

이것은 stringify 연산자 “#”을 사용하여 GCC에서 수행 할 수 있지만 두 단계가 필요합니다.

#define XSTR(x) STR(x)
#define STR(x) #x

매크로 값은 다음과 같이 표시 될 수 있습니다.

#pragma message "The value of ABC: " XSTR(ABC)

참조 : 3.4 gcc 온라인 문서의 Stringification.

작동 원리 :

전처리 기는 인용 된 문자열을 이해하고 일반 텍스트와 다르게 처리합니다. 문자열 연결은 이러한 특수 처리의 예입니다. 메시지 pragma에는 인용 된 문자열 인 인수가 필요합니다. 인수에 둘 이상의 구성 요소가있는 경우 문자열 연결이 적용될 수 있도록 모두 문자열이어야합니다. 전처리 기는 인용되지 않은 문자열이 인용 된 것처럼 처리되어야한다고 가정 할 수 없습니다. 그렇다면 :

#define ABC 123
int n = ABC;

컴파일되지 않습니다.

이제 다음을 고려하십시오.

#define ABC abc
#pragma message "The value of ABC is: " ABC

이는

#pragma message "The value of ABC is: " abc

abc (따옴표 없음)를 앞의 문자열과 연결할 수 없기 때문에 전 처리기 경고가 발생합니다.

이제 전 처리기 스트링 화를 고려하십시오 (한때 스트링 화라고 불렸던 문서의 링크는 수정 된 용어를 반영하도록 변경되었습니다. 두 용어 모두 똑같이 혐오스러운 표현입니다. 물론 올바른 용어는 스트링 화입니다. 업데이트 할 준비를하십시오. 귀하의 링크.)) 연산자. 이것은 매크로의 인수에 대해서만 작동하며 확장되지 않은 인수를 큰 따옴표로 묶인 인수로 대체합니다. 그러므로:

#define STR(x) #x
char *s1 = "abc";
char *s2 = STR(abc);

s1과 s2에 동일한 값을 할당합니다. gcc -E를 실행하면 출력에서이를 볼 수 있습니다. 아마도 STR은 ENQUOTE와 같은 이름으로 더 잘 명명 될 것입니다.

이것은 인용되지 않은 항목 주위에 인용 부호를 넣는 문제를 해결합니다. 이제 문제는 인수가 매크로 인 경우 매크로가 확장되지 않는다는 것입니다. 이것이 두 번째 매크로가 필요한 이유입니다. XSTR은 인수를 확장 한 다음 STR을 호출하여 확장 된 값을 따옴표로 묶습니다.


답변

BOOST_PP_STRINGIZE C ++에는 훌륭한 솔루션이지만 일반 C에는 적합하지 않습니다.

다음은 GNU CPP에 대한 솔루션입니다.

/* Some test definition here */
#define DEFINED_BUT_NO_VALUE
#define DEFINED_INT 3
#define DEFINED_STR "ABC"

/* definition to expand macro then apply to pragma message */
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define VAR_NAME_VALUE(var) #var "="  VALUE(var)

/* Some example here */
#pragma message(VAR_NAME_VALUE(NOT_DEFINED))
#pragma message(VAR_NAME_VALUE(DEFINED_BUT_NO_VALUE))
#pragma message(VAR_NAME_VALUE(DEFINED_INT))
#pragma message(VAR_NAME_VALUE(DEFINED_STR))

위의 정의 결과 :

test.c:10:9: note: #pragma message: NOT_DEFINED=NOT_DEFINED
test.c:11:9: note: #pragma message: DEFINED_BUT_NO_VALUE=
test.c:12:9: note: #pragma message: DEFINED_INT=3
test.c:13:9: note: #pragma message: DEFINED_STR="ABC"

들어 “interger로 정의” , “문자열로 정의”“정의되어 있지만 값” 변수는, 그들은 잘 작동하지 않습니다. “정의되지 않은” 변수에 대해서만 원래 변수 이름과 똑같이 표시됩니다. 익숙해야합니다. 그렇지 않으면 누군가가 더 나은 솔루션을 제공 할 수 있습니다.


답변

Visual C ++를 사용하는 경우 다음을 사용할 수 있습니다 #pragma message.

#include <boost/preprocessor/stringize.hpp>
#pragma message("BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION))

편집 : 링크에 대한 LB 감사합니다

분명히 GCC에 해당하는 것은 (테스트되지 않음) :

#pragma message "BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION)


답변

내가 아는 한 ‘#error’는 문자열 만 인쇄 하므로 실제로 따옴표를 사용할 필요도 없습니다 .

“BOOST_VERSION”을 사용하여 의도적으로 잘못된 코드를 다양하게 작성해 보셨습니까? 아마도 “blah [BOOST_VERSION] = foo;” “문자열 리터럴 1.2.1은 배열 주소로 사용할 수 없습니다”와 같은 메시지가 표시됩니다. 예쁜 오류 메시지는 아니지만 적어도 관련 값을 보여줄 것입니다. 값을 알려주는 컴파일 오류를 찾을 때까지 놀 수 있습니다.


답변

부스트없이 :

  1. 동일한 매크로를 다시 정의하면 컴파일러 HIMSELF가 경고를 제공합니다.

  2. 경고에서 이전 정의의 위치를 ​​볼 수 있습니다.

  3. 이전 정의의 vi 파일.

ambarish@axiom:~/cpp$ g++ shiftOper.cpp
shiftOper.cpp:7:1: warning: "LINUX_VERSION_CODE" redefined
shiftOper.cpp:6:1: warning: this is the location of the previous definition

#define LINUX_VERSION_CODE 265216
#define LINUX_VERSION_CODE 666

int main ()
{

}


답변

Microsoft C / C ++에서는 기본 제공을 사용하여 _CRT_STRINGIZE()상수를 인쇄 할 수 있습니다 . 내 stdafx.h파일 중에는 다음과 같은 조합이 포함되어 있습니다.

#pragma message("_MSC_VER      is " _CRT_STRINGIZE(_MSC_VER))
#pragma message("_MFC_VER      is " _CRT_STRINGIZE(_MFC_VER))
#pragma message("_ATL_VER      is " _CRT_STRINGIZE(_ATL_VER))
#pragma message("WINVER        is " _CRT_STRINGIZE(WINVER))
#pragma message("_WIN32_WINNT  is " _CRT_STRINGIZE(_WIN32_WINNT))
#pragma message("_WIN32_IE     is " _CRT_STRINGIZE(_WIN32_IE))
#pragma message("NTDDI_VERSION is " _CRT_STRINGIZE(NTDDI_VERSION))

다음과 같이 출력됩니다.

_MSC_VER      is 1915
_MFC_VER      is 0x0E00
_ATL_VER      is 0x0E00
WINVER        is 0x0600
_WIN32_WINNT  is 0x0600
_WIN32_IE     is 0x0700
NTDDI_VERSION is 0x06000000


답변

#define a <::BOOST_VERSION>
#include a

MSVC2015 : 치명적인 오류 C1083 : 포함 파일을 열 수 없음 : ‘:: 106200’: 해당 파일 또는 디렉터리가 없습니다.

preprocess to file유효하지 않은 토큰이있는 경우에도이 활성화 된 경우에도 작동합니다 .

#define a <::'*/`#>
#include a

MSVC2015 : 치명적인 오류 C1083 : 포함 파일을 열 수 없음 : ‘::’* /`# ‘: 해당 파일 또는 디렉터리가
없습니다 . GCC4.x : 경고 :’문자 [-Winvalid-pp-token]
#define a <:: ‘* /`#>