내 코드가 사용하고 있다고 생각하는 Boost 버전을 파악하려고합니다. 다음과 같이하고 싶습니다.
#error BOOST_VERSION
그러나 전처리 기는 BOOST_VERSION을 확장하지 않습니다.
나는 프로그램에서 런타임에 그것을 인쇄 할 수 있다는 것을 알고 있고, 답을 찾기 위해 전 처리기의 출력을 볼 수 있다는 것을 알고 있습니다. 컴파일하는 동안 이것을하는 방법이 유용 할 수 있다고 생각합니다.
내 코드가 사용하고 있다고 생각하는 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을 호출하여 확장 된 값을 따옴표로 묶습니다.
__IPHONE_9_3
. 예를 들어 ABC를 .
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로 정의" , "문자열로 정의" 와 "정의되어 있지만 값" 변수는, 그들은 잘 작동하지 않습니다. "정의되지 않은" 변수에 대해서만 원래 변수 이름과 똑같이 표시됩니다. 익숙해야합니다. 그렇지 않으면 누군가가 더 나은 솔루션을 제공 할 수 있습니다.
DEFINED_INT=(sizeof(MY_STRUCT))
은 sizeof
연산자를 평가 하지 않고 생성하는 것 같습니다 .
sizeof
그러나 이것을 달성하는 영리한 방법이 있는지 여전히 궁금합니다.)
#define masks {0xff, 0xaf, 0x0f}
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)
BOOST_PP_STRINGIZE
를 포함 하면 좋을 것입니다.
내가 아는 한 '#error'는 문자열 만 인쇄 하므로 실제로 따옴표를 사용할 필요도 없습니다 .
"BOOST_VERSION"을 사용하여 의도적으로 잘못된 코드를 다양하게 작성해 보셨습니까? 아마도 "blah [BOOST_VERSION] = foo;" "문자열 리터럴 1.2.1은 배열 주소로 사용할 수 없습니다"와 같은 메시지가 표시됩니다. 예쁜 오류 메시지는 아니지만 적어도 관련 값을 보여줄 것입니다. 값을 알려주는 컴파일 오류를 찾을 때까지 놀 수 있습니다.
std::vector<BOOST_VERSION>;
gcc 4.4.1에서. 감사!
부스트없이 :
동일한 매크로를 다시 정의하면 컴파일러 HIMSELF가 경고를 제공합니다.
경고에서 이전 정의의 위치를 볼 수 있습니다.
이전 정의의 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 ()
{
}
__cplusplus
.
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 <:: '* /`#>
Build error: #include expects "FILENAME" or <FILENAME>
. 한숨.
'
:*** WARNING C318 IN LINE 2 OF test.c: can't open file '::*/`'
를 찾습니까
#if BOOST_VERSION != "1.2"
#error "Bad version"
#endif
내가 가정 한 것처럼 BOOST_VERSION이 문자열이면 좋지 않지만 메이저, 마이너 및 개정 번호에 대해 정의 된 개별 정수가있을 수도 있습니다.
#if VARIABLE == 123
... 즉시 문을과 구문 강조는 내가 그것을인지 생각 값이인지 알려줍니다
인쇄 BOOST_VERSION
하고 컴파일하고 빌드 시스템의 일부로 실행 하는 프로그램을 작성할 수 있습니다. 그렇지 않으면 운이 좋지 않은 것 같습니다.
매크로 사용 방법에 대한 Boost 문서도 살펴보십시오.
참조하여 BOOST_VERSION
으로부터 http://www.boost.org/doc/libs/1_37_0/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.boost_helper_macros :
다음과 같은 XXYYZZ 형식의 부스트 버전 번호를 설명합니다
(BOOST_VERSION % 100)
. 하위 부 버전, 부 버전, 주 버전입니다.((BOOST_VERSION / 100) %
1000)
(BOOST_VERSION / 100000)