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

发布于 2024-08-07 10:34:00 字数 190 浏览 5 评论 0原文

我试图找出我的代码认为它使用的 Boost 版本。我想做这样的事情:

#error BOOST_VERSION

但预处理器不会扩展 BOOST_VERSION。

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

I am trying to figure out what version of Boost my code thinks it's using. I want to do something like this:

#error BOOST_VERSION

but the preprocessor does not expand BOOST_VERSION.

I know I could print it out at run-time from the program, and I know I could look at the output of the preprocessor to find the answer. I feel like having a way of doing this during compilation could be useful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

凉月流沐 2024-08-14 10:34:00

我知道这距离原始查询已经过去很长时间了,但这可能仍然有用。

这可以在 GCC 中使用字符串化运算符“#”来完成,但需要首先定义两个附加阶段。

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

现在考虑预处理器 stringize (曾经被称为 stringification,文档中的链接已更改以反映修订后的术语。(顺便说一句,这两个术语同样令人讨厌。当然,正确的术语是 stringifaction。准备好更新您的链接。))运营商。这只作用于宏的参数,并将未展开的参数替换为用双引号括起来的参数。因此:

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

将为 s1 和 s2 分配相同的值。如果运行 gcc -E 您可以在输出中看到这一点。也许 STR 更适合命名为 ENQUOTE 之类的名称。

这解决了在未加引号的项目周围加上引号的问题,现在的问题是,如果参数是宏,则宏将不会被扩展。这就是需要第二个宏的原因。 XSTR 扩展其参数,然后调用 STR 将扩展的值放入引号中。

I know that this is a long time after the original query, but this may still be useful.

This can be done in GCC using the stringify operator "#", but it requires two additional stages to be defined first.

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

The value of a macro can then be displayed with:

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

See: 3.4 Stringification in the gcc online documentation.

How it works:

The preprocessor understands quoted strings and handles them differently from normal text. String concatenation is an example of this special treatment. The message pragma requires an argument that is a quoted string. When there is more than one component to the argument then they must all be strings so that string concatenation can be applied. The preprocessor can never assume that an unquoted string should be treated as if it were quoted. If it did then:

#define ABC 123
int n = ABC;

would not compile.

Now consider:

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

which is equivalent to

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

This causes a preprocessor warning because abc (unquoted) cannot be concatenated with the preceding string.

Now consider the preprocessor stringize (Which was once called stringification, the links in the documentation have been changed to reflect the revised terminology. (Both terms, incidentally, are equally detestable. The correct term is, of course, stringifaction. Be ready to update your links.)) operator. This acts only on the arguments of a macro and replaces the unexpanded argument with the argument enclosed in double quotes. Thus:

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

will assign identical values to s1 and s2. If you run gcc -E you can see this in the output. Perhaps STR would be better named something like ENQUOTE.

This solves the problem of putting quotes around an unquoted item, the problem now is that, if the argument is a macro, the macro will not be expanded. This is why the second macro is needed. XSTR expands its argument, then calls STR to put the expanded value into quotes.

々眼睛长脚气 2024-08-14 10:34:00

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"

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

BOOST_PP_STRINGIZE seems a excellent solution for C++, but not for regular C.

Here is my solution for 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))

Above definitions result in:

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"

For "defined as interger", "defined as string", and "defined but no value" variables , they work just fine. Only for "not defined" variable, they displayed exactly the same as original variable name. You have to used to it -- or maybe someone can provide a better solution.

羅雙樹 2024-08-14 10:34:00

如果您使用的是 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)

If you are using Visual C++, you can use #pragma message:

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

Edit: Thanks to LB for link

Apparently, the GCC equivalent is (not tested):

#pragma message "BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION)
翻了热茶 2024-08-14 10:34:00

据我所知 '#error' 只会打印字符串,事实上你甚至不需要使用引号

您是否尝试过使用“BOOST_VERSION”编写各种故意不正确的代码?也许类似于“blah[BOOST_VERSION] = foo;”会告诉你类似“字符串文字 1.2.1 不能用作数组地址”之类的信息。这不会是一个漂亮的错误消息,但至少它会向您显示相关的值。您可以尝试一下,直到找到确实告诉您该值的编译错误。

As far as I know '#error' only will print strings, in fact you don't even need to use quotes.

Have you tried writing various purposefully incorrect code using "BOOST_VERSION"? Perhaps something like "blah[BOOST_VERSION] = foo;" will tell you something like "string literal 1.2.1 cannot be used as an array address". It won't be a pretty error message, but at least it'll show you the relevant value. You can play around until you find a compile error that does tell you the value.

不离久伴 2024-08-14 10:34:00

没有 boost :

  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 ()
{

}

Without boost :

  1. define same macro again and compiler HIMSELF will give warning.

  2. From warning you can see location of the previous definition.

  3. vi file of previous definition .

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 ()
{

}
柏林苍穹下 2024-08-14 10:34:00

在 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

In Microsoft C/C++, you can use the built-in _CRT_STRINGIZE() to print constants. Many of my stdafx.h files contain some combination of these:

#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)) 

and outputs something like this:

_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
海拔太高太耀眼 2024-08-14 10:34:00
#define a <::BOOST_VERSION>
#include a

MSVC2015:致命错误 C1083:无法打开包含文件:'::106200':没有这样的文件或目录

优点

  • 适用于内置宏
  • 即使启用了预处理到文件,即使存在无效令牌,也可以工作:
#define a <::'*/`#>
#include a

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

缺点

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

更新

对于 GCC 4.7.x 及更低版本,输出会引发错误:

错误:#include 需要“FILENAME”或

要解决此问题,您可以更改前缀:

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

MSVC2015: fatal error C1083: Cannot open include file: '::106200': No such file or directory

Pros:

  • Works on builtin macroses
  • Works even if preprocess to file is enabled, even if invalid tokens are present:
#define a <::'*/`#>
#include a

MSVC2015: fatal error C1083: Cannot open include file: '::'*/`#': No such file or directory
GCC4.x: warning: missing terminating ' character [-Winvalid-pp-token]
#define a <::'*/`#>

Cons:

  • Sometime fails because of invalid characters in the include file path. Can be fixed by change a prefix (see update section below).

Update:

For GCC 4.7.x and lower the output throws the error:

error: #include expects "FILENAME" or <FILENAME>

To fix that you can change the prefix:

#define a <.__cplusplus>
#include a
fatal error: .201103L: No such file or directory
花开浅夏 2024-08-14 10:34:00

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

You could also preprocess the source file and see what the preprocessor value evaluates to.

记忆で 2024-08-14 10:34:00

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

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

Looking at the output of the preprocessor is the closest thing to the answer you ask for.

I know you've excluded that (and other ways), but I'm not sure why. You have a specific enough problem to solve, but you have not explained why any of the "normal" methods don't work well for you.

滥情稳全场 2024-08-14 10:34:00

您可以编写一个程序来打印 BOOST_VERSION 并将其作为构建系统的一部分进行编译和运行。不然我觉得你运气不好。

You could write a program that prints out BOOST_VERSION and compile and run it as part of your build system. Otherwise, I think you're out of luck.

眉目亦如画i 2024-08-14 10:34:00

您是否正在寻找

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

Not Great if BOOST_VERSION 是一个字符串,就像我假设的那样,但也可能为主要、次要和修订号定义了单独的整数。

Are you looking for

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

Not great if BOOST_VERSION is a string, like I've assumed, but there may also be individual integers defined for the major, minor and revision numbers.

如何视而不见 2024-08-14 10:34:00

BOOST_VERSION 在 boost 头文件 version.hpp 中定义。

BOOST_VERSION is defined in the boost header file version.hpp.

盗琴音 2024-08-14 10:34:00

另请参阅 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

描述boost版本号
XXYYZZ 格式如下:
(BOOST_VERSION % 100) 是次要的
版本,((BOOST_VERSION / 100) %
1000) 是次要版本,并且
(BOOST_VERSION / 100000) 是主要的
版本。

Take a look at the Boost documentation as well, regarding how you are using the macro:

In reference to BOOST_VERSION, from 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:

Describes the boost version number in
XXYYZZ format such that:
(BOOST_VERSION % 100) is the sub-minor
version, ((BOOST_VERSION / 100) %
1000) is the minor version, and
(BOOST_VERSION / 100000) is the major
version.

调妓 2024-08-14 10:34:00

在编译时打印扩展的宏值

这是@Jackie Yeh 的答案的扩展。

神奇的助手宏,经过我的一些小调整:

// Helper macros to print the value of a macro at compile-time
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"

使用它们:

#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)

警告:如果宏未定义,它的名称将再次打印出来!因此,如果您的宏名为 MY_MACRO,但您从未定义它,则执行以下操作:

#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_MACRO)

...将打印出如下内容:

../main.c:1000:63: note: #pragma message: MY_MACRO=`MY_MACRO`

因此,搜索 #pragma message: 在构建输出中查看打印的宏值。并且,在编译时查找 MY_MACRO=`MY_MACRO` 类型输出,这是 MY_MACRO 未定义的明确标志!

这让我有一段时间感到困惑,我失去了很多时间没有意识到这一点。


我想证明这也适用于代码块。所以,这是我的完整示例:

macro_print_macro_values_at_compile_time.c 来自我的 eRCaGuy_hello_world 存储库:

///usr/bin/env ccache gcc -Wall -Wextra -Werror -O3 -std=gnu17 "$0" -o /tmp/a -lm && /tmp/a "$@"; exit
// For the line just above, see my answer here: https://stackoverflow.com/a/75491834/4561887

#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h>  // For `uint8_t`, `int8_t`, etc.
#include <stdio.h>   // For `printf()`

// Various macro definitions to test
#define DEFINED_BUT_NO_VALUE
#define MY_INT 3
#define MY_STR "ABC"
#define MY_CODE_BLOCK           \
    do                          \
    {                           \
        printf("Hi 1.\n");      \
    } while (0)
//
// NB: the `#pragma message` output of the above macro is substantially different if I define it as
// `MY_CODE_BLOCK()` instead, and call it as such inside `main()`! Try it out and you'll see.
//
#define MY_CODE_BLOCK2          \
    {                           \
        printf("Hi 2.\n");      \
    }

// Helper macros to print the value of a macro at compile-time
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"

// Example prints at compile-time
#pragma message PRINT_MACRO_AT_COMPILE_TIME(NOT_DEFINED)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(DEFINED_BUT_NO_VALUE)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_STR)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK2)


// int main(int argc, char *argv[])  // alternative prototype
int main()
{
    MY_CODE_BLOCK;
    MY_CODE_BLOCK2;
    printf("Hello World.\n\n");

    return 0;
}

构建并运行命令,并输出,在 C 和 C++ 中:

在 C 中:

eRCaGuy_hello_world/c$ ./macro_print_macro_values_at_compile_time.c
./macro_print_macro_values_at_compile_time.c:74:9: note: ‘#pragma message: NOT_DEFINED=`NOT_DEFINED`’
   74 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(NOT_DEFINED)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:75:9: note: ‘#pragma message: DEFINED_BUT_NO_VALUE=``’
   75 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(DEFINED_BUT_NO_VALUE)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:76:9: note: ‘#pragma message: MY_INT=`3`’
   76 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:77:9: note: ‘#pragma message: MY_STR=`"ABC"`’
   77 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_STR)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:78:9: note: ‘#pragma message: MY_CODE_BLOCK=`do { printf("Hi 1.\n"); } while (0)`’
   78 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:79:9: note: ‘#pragma message: MY_CODE_BLOCK2=`{ printf("Hi 2.\n"); }`’
   79 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK2)
      |         ^~~~~~~
Hi 1.
Hi 2.
Hello World.

或者在 C++ 中:

eRCaGuy_hello_world/c$ g++ -Wall -Wextra -Werror -O3 -std=gnu++17 macro_print_macro_values_at_compile_time.c -o bin/a && bin/a
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: NOT_DEFINED=`NOT_DEFINED`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:74:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   74 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(NOT_DEFINED)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: DEFINED_BUT_NO_VALUE=``’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:75:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   75 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(DEFINED_BUT_NO_VALUE)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_INT=`3`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:76:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   76 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_STR=`"ABC"`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:77:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   77 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_STR)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_CODE_BLOCK=`do { printf("Hi 1.\n"); } while (0)`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:78:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   78 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_CODE_BLOCK2=`{ printf("Hi 2.\n"); }`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:79:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   79 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK2)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
Hi 1.
Hi 2.
Hello World.

相邻相关

  1. 我对 打印 (sizeof( )) C 和 C++ 编译时错误消息中的类型或变量

Print expanded macro values at compile-time

This is an extension of @Jackie Yeh's answer here.

The magic helper macros, with my minor tweaks:

// Helper macros to print the value of a macro at compile-time
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"

To use them:

#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)

A word of caution: if the macro is not defined, its name will just be printed out again! So, if your macro is called MY_MACRO, but you never define it, then doing this:

#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_MACRO)

...will print out something like this:

../main.c:1000:63: note: #pragma message: MY_MACRO=`MY_MACRO`

So, do a search for #pragma message: in your build output to see the printed macro values. And, look for MY_MACRO=`MY_MACRO` type output when compiling as a clear sign that MY_MACRO is not defined!

This threw me off for a while and I lost a lot of time not realizing this.


I want to show that this works with code blocks too. So, here's my full example:

macro_print_macro_values_at_compile_time.c from my eRCaGuy_hello_world repo:

///usr/bin/env ccache gcc -Wall -Wextra -Werror -O3 -std=gnu17 "$0" -o /tmp/a -lm && /tmp/a "$@"; exit
// For the line just above, see my answer here: https://stackoverflow.com/a/75491834/4561887

#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h>  // For `uint8_t`, `int8_t`, etc.
#include <stdio.h>   // For `printf()`

// Various macro definitions to test
#define DEFINED_BUT_NO_VALUE
#define MY_INT 3
#define MY_STR "ABC"
#define MY_CODE_BLOCK           \
    do                          \
    {                           \
        printf("Hi 1.\n");      \
    } while (0)
//
// NB: the `#pragma message` output of the above macro is substantially different if I define it as
// `MY_CODE_BLOCK()` instead, and call it as such inside `main()`! Try it out and you'll see.
//
#define MY_CODE_BLOCK2          \
    {                           \
        printf("Hi 2.\n");      \
    }

// Helper macros to print the value of a macro at compile-time
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"

// Example prints at compile-time
#pragma message PRINT_MACRO_AT_COMPILE_TIME(NOT_DEFINED)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(DEFINED_BUT_NO_VALUE)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_STR)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK2)


// int main(int argc, char *argv[])  // alternative prototype
int main()
{
    MY_CODE_BLOCK;
    MY_CODE_BLOCK2;
    printf("Hello World.\n\n");

    return 0;
}

Build and run commands, and output, in both C and C++:

In C:

eRCaGuy_hello_world/c$ ./macro_print_macro_values_at_compile_time.c
./macro_print_macro_values_at_compile_time.c:74:9: note: ‘#pragma message: NOT_DEFINED=`NOT_DEFINED`’
   74 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(NOT_DEFINED)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:75:9: note: ‘#pragma message: DEFINED_BUT_NO_VALUE=``’
   75 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(DEFINED_BUT_NO_VALUE)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:76:9: note: ‘#pragma message: MY_INT=`3`’
   76 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:77:9: note: ‘#pragma message: MY_STR=`"ABC"`’
   77 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_STR)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:78:9: note: ‘#pragma message: MY_CODE_BLOCK=`do { printf("Hi 1.\n"); } while (0)`’
   78 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK)
      |         ^~~~~~~
./macro_print_macro_values_at_compile_time.c:79:9: note: ‘#pragma message: MY_CODE_BLOCK2=`{ printf("Hi 2.\n"); }`’
   79 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK2)
      |         ^~~~~~~
Hi 1.
Hi 2.
Hello World.

Or, in C++:

eRCaGuy_hello_world/c$ g++ -Wall -Wextra -Werror -O3 -std=gnu++17 macro_print_macro_values_at_compile_time.c -o bin/a && bin/a
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: NOT_DEFINED=`NOT_DEFINED`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:74:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   74 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(NOT_DEFINED)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: DEFINED_BUT_NO_VALUE=``’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:75:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   75 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(DEFINED_BUT_NO_VALUE)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_INT=`3`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:76:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   76 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_STR=`"ABC"`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:77:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   77 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_STR)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_CODE_BLOCK=`do { printf("Hi 1.\n"); } while (0)`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:78:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   78 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_CODE_BLOCK2=`{ printf("Hi 2.\n"); }`’
   71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
      |                                                               ^~~
macro_print_macro_values_at_compile_time.c:79:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
   79 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK2)
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
Hi 1.
Hi 2.
Hello World.

Adjacently-related

  1. My answer on Printing the size of (sizeof()) a type or variable in an error message at compile time in both C and C++
青朷 2024-08-14 10:34:00

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

#define BOOST_VERSION 等等

Instead of #error, try redefining the macro, just before it is being used. Compilation will fail and compiler will provide the current value it thinks applies to the macro.

#define BOOST_VERSION blah

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文