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

我正试图找出我的代码认为它正在使用的 Boost 的哪个版本。我想这样做:

#error BOOST_VERSION

但是预处理器不展开 BOOST _ VERION。

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

156422 次浏览

您可以编写一个程序,打印出 BOOST_VERSION并编译和运行它作为构建系统的一部分。否则,我觉得你就不走运了。

据我所知,“ # error”只会打印字符串,实际上是 你甚至不需要用引号

您是否尝试过使用“ BOOST _ VERION”编写各种有目的的错误代码?也许类似于“ ba [ BOOST _ VERION ] = foo;”的内容会告诉您类似于“ string Literal1.2.1不能用作数组地址”的内容。这不会是一个很好的错误消息,但至少它会向您显示相关的值。在找到确实告诉您值的编译错误之前,您可以一直玩下去。

你在找

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

如果像我假设的那样,BOOST _ VERION 是一个字符串,那就不太好了,但是可能还有为主要、次要和修订号定义的单个整数。

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

查看预处理器的输出是最接近您所要求的答案的事情。

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

在 BOOST 头文件 version. hpp 中定义了 BOOST _ VERION。

如果使用 Visual C + + ,可以使用 #pragma message:

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

编辑: 感谢 LB 的链接

显然,海湾合作委员会的等价物是(未经测试的) :

#pragma message "BOOST_VERSION=" BOOST_PP_STRINGIZE(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) 是主要的 版本。

对于 C + + 来说,BOOST_PP_STRINGIZE似乎是一个很好的解决方案,但对于普通 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)

参见: 3.4在 gcc 在线文档中的 Stringification。

工作原理:

预处理器理解带引号的字符串,并以不同于普通文本的方式处理它们。字符串连接就是这种特殊处理的一个例子。消息杂注需要一个引号字符串参数。当参数有多个组件时,它们必须都是字符串,这样才能应用字符串串联。预处理程序永远不能假定未引号的字符串应该被当作引号来处理。如果是这样的话:

#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 (未引号)不能与前面的字符串连接。

现在考虑一下预处理器 stringize (它曾经被称为 stringize,文档中的链接已经被修改以反映修订后的术语。(顺便说一句,这两个词都同样令人厌恶。当然,正确的说法是严格控制。准备更新你的链接。)接线员。这只作用于宏的参数,并用双引号中的参数替换未展开的参数。因此:

#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: 无法打开包含文件: “ : : 106200”: 没有这样的文件或目录

优点 :

  • 在内置的巨型玫瑰上工作
  • 即使启用了 preprocess to file,即使存在无效的令牌,也可以正常工作:
#define a <::'*/`#>
#include a
MSVC2015 : 致命错误 C1083: 无法打开包含文件:’: :’*/‘ #’: 没有这样的文件或目录
GCC4.x : 警告: 缺少终止’字符[-Wvalid- pp-token ]
# 释义一个 < : :’*/’# >

缺点 :

  • 有时会因为包含文件路径中的无效字符而失败。可以通过更改前缀来修复(请参阅下面的更新部分)。

更新 :

对于 GCC 4.7.x 或更低的值,输出会出现错误:

包括期望“ FILENAME”或 < FILENAME >

要修复您可以更改前缀的问题:

#define a <.__cplusplus>
#include a
fatal error: .201103L: No such file or directory

没有推动力:

  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

尝试在使用宏之前重新定义它,而不是 # error。编译将失败,编译器将提供它认为应用于宏的当前值。

定义 BOOST _ VERION 之类的