小编典典

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

all

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

#error BOOST_VERSION

但预处理器不会扩展 BOOST_VERSION。

我知道我可以在程序运行时将其打印出来,并且我知道我可以查看预处理器的输出以找到答案。我觉得在编译期间有一种方法可能会很有用。


阅读 84

收藏
2022-08-20

共1个答案

小编典典

我知道这是在原始查询之后很长时间,但这可能仍然有用。

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

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

然后可以通过以下方式显示宏的值:

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

请参阅:gcc 在线文档中的 3.4 字符串化。

这个怎么运作:

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

#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
将扩展值放入引号中。

2022-08-20