在C预处理器中避免双重macros观replace

这是一个简单的小C程序,让我困惑了一会儿:

#include <stdio.h> #define STR1(x) #x #define STR(x) STR1(x) int main(void) { printf("%s\n", STR(MYDEF)); } 

这只是使用标准的string化双定义技术将stringMYDEF #define的值打印出来。

使用gcc -DMYDEF=abc prog.c编译(在Linux上)运行结果,并不奇怪,它打印出'abc'。

但是改变gcc -DMYDEF=linux prog.c的值,打印的结果不是'linux',而是'1'。

所以这让我困惑了一下,但是当然是因为gcc(在Linux上)发现了一个名为'linux'的内置的#define,其值为'1',而STR(x)macros最后将MYDEF扩展为“linux”,然后将linux扩展为“1”。

在我真正的程序中(这比上面的小testing要复杂得多),我用一种不同的(可能更好的)方式来处理这个事情,但是这让我好奇……是否有一个简单的小macros技术可以避免这个双重replace,并使程序打印出'linux'? 我知道我可以添加一个-U或#undef的Linux,但是这感觉有点笨拙。

我以为所有内置的#define都以下划线(通常是双下划线)开头,但我猜不是。

Solutions Collecting From Web of "在C预处理器中避免双重macros观replace"

没有办法只扩展宏一次,总是有一个重新扫描进行进一步的替换(当然,从来没有递归)。 在某些情况下,宏根本没有展开(就像#运算符一样),这就是为什么你需要像在你的例子中那样使用两个#define的额外替换级别。

在ISO C中,没有前导下划线的标识符可以自由使用(不是所有的都是精确的)。 为了向后兼容,GNU C语言默认定义了一些其他的宏(比如linux ),不过他们计划在未来删除这些宏。

要在你的机器上得到这样的宏列表,你可以这样做:

 $ echo | gcc -std=gnu99 -E -dM - | grep -v '# *define *_' #define unix 1 #define linux 1 #define i386 1 

对于较早的Gcc的ISO C( -ansi / -std=c89-std=c99-std=c11 / -std=c1x )选项,这些宏没有定义:

 $ cat test.c #define STR1(x) #x #define STR(x) STR1(x) STR(MYDEF); STR1(MYDEF); $ gcc -std=gnu99 -DMYDEF=linux -E test.c # 1 "test.c" # 1 "<command-line>" # 1 "test.c" "1"; "MYDEF"; $ gcc -std=c99 -DMYDEF=linux -E test.c # 1 "test.c" # 1 "<command-line>" # 1 "test.c" "linux"; "MYDEF"; 

在ISO C模式下,这些宏正确地位于保留的名称空间中:

 $ echo | gcc -std=c99 -E -dM - | grep linux #define __linux 1 #define __linux__ 1 #define __gnu_linux__ 1 

我在gcc手册中看到,您可以使用-ansi选项来关闭预定义的宏,例如“linux”

 gcc -ansi -DMYDEF=linux prog.c