Macros 如何在编译时显示#define的值?

Macros 如何在编译时显示#define的值?,macros,c-preprocessor,boost-preprocessor,Macros,C Preprocessor,Boost Preprocessor,我正试图弄清楚我的代码认为它使用的是哪个版本的Boost。我想这样做: _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 #错误升级(U版本 但预处理器并不扩展BOOST_版本 我知道我可以在运行时从程序中打

我正试图弄清楚我的代码认为它使用的是哪个版本的Boost。我想这样做:

_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
#错误升级(U版本

但预处理器并不扩展BOOST_版本


我知道我可以在运行时从程序中打印出来,我知道我可以查看预处理器的输出来找到答案。我觉得在编译过程中有一种方法是有用的。

您可以编写一个程序,打印出
BOOST\u版本
,并作为构建系统的一部分进行编译和运行。否则,我认为你运气不好。

据我所知,“#error”实际上只会打印字符串

您是否尝试过使用“BOOST_版本”编写各种故意不正确的代码?也许类似“blah[BOOST_VERSION]=foo;”的内容会告诉您类似“string literal 1.2.1不能用作数组地址”。这不会是一个很好的错误消息,但至少它会向您显示相关的值。您可以一直玩到发现一个编译错误,该错误会告诉您该值。

您在找什么

#if BOOST_VERSION != "1.2"
#error "Bad version"
#endif

如果BOOST_版本是一个字符串(如我所假设的)则不太好,但也可能会为主要变量定义单个整数,次要和修订号。

您还可以预处理源文件,并查看预处理器值的计算结果。

查看预处理器的输出与您要求的答案最接近


我知道你已经排除了这一点(以及其他方式),但我不知道为什么。你有一个足够具体的问题需要解决,但是你没有解释为什么任何“正常”的方法对你来说都不太好。

< P> STOSTYVE版本是在Boost头文件版本中定义的。Hpp.< /P> < P>如果你使用Visual C++,你可以使用<代码>
#include <boost/preprocessor/stringize.hpp>
#pragma message("BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION))

还可以查看Boost文档,了解如何使用宏:

参考
BOOST\u版本
,来自:

描述中的boost版本号 XXYYZZ格式,以便:
(BOOST\u版本%100)
是次小调 版本,
((BOOST\u version/100)%
1000)
是次要版本,并且
(BOOST\u VERSION/100000)
是主要的 版本


<代码> BooStPypppStrugEng/<代码>似乎是一个优秀的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"

对于“定义为整数”“定义为字符串”“定义但无值”变量,它们工作正常。仅对于“未定义”变量,其显示与原始变量名称完全相同。你必须习惯它——或者也许有人可以提供更好的解决方案。

我知道在最初的查询之后,这需要很长时间,但这可能仍然有用

这可以在GCC中使用stringify操作符“#”完成,但它需要两个阶段

#define XSTR(x) STR(x)
#define STR(x) #x
然后,宏的值可以显示为:

#pragma message "The value of ABC: " XSTR(ABC)
参见:gcc在线文档中的3.4严格化

工作原理:

预处理器理解带引号的字符串,并以与普通文本不同的方式处理它们。字符串连接就是这种特殊处理的一个例子。消息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(无引号)不能与前面的字符串连接

现在考虑预处理器StrugI化(这曾经被称为严格化),文档中的链接已经被更改以反映修改后的术语。(顺便提一下,这两个术语都是同样可憎的。正确的术语是,当然,STRIGIFACTION。准备好更新您的链接。))操作员。这只作用于宏的参数,并用双引号中的参数替换未展开的参数。因此:

#define STR(x) #x
char *s1 = "abc";
char *s2 = STR(abc);
将为s1和s2分配相同的值。如果运行gcc-E,您可以在输出中看到这一点。也许STR的名字应该更像ENQUOTE

这解决了在未加引号的项周围加引号的问题,现在的问题是,如果参数是宏,宏将不会展开。这就是为什么需要第二个宏。XSTR展开它的参数,然后调用STR将展开的值放在引号中

#define a <::BOOST_VERSION>
#include a
MSVC2015:致命错误C1083:无法打开包含文件:':'*/`#':没有此类文件或目录
GCC4.x:警告:缺少终止字符[-Winvalid pp token]
#定义一个无增压的:

  • 再次定义同一个宏,编译器将发出警告

  • 从“警告”中可以看到上一个定义的位置

  • 先前定义的vi文件


  • 在Microsoft C/C++中,可以使用内置的
    \u CRT\u 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
    
    在使用宏之前,尝试重新定义宏,而不是#error。编译将失败,编译器将提供它认为适用于宏的当前值


    #定义BOOST_VERSION blah

    对于在标题中定义的软件版本,您可能是安全的(这是一个很好的答案)。但作为一种通用解决方案,一个可能的缺点是让您的测试应用程序和实际应用程序具有相同的#define值-根据它们的包含路径,其他可用于设置该值的#define,即传递给编译器的cflag,
    #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