微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

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

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

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

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

在c#中获取进程的线程数

使用BitmapEncoder生成时如何在循环中重复GIF

从c ++更新系统环境variables

位图正在拉伸,而不是平铺

在线唤醒执行

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

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

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

用非零值填充内存比用零填充内存慢吗?

内核如何知道哪个驱动程序属于哪个外设?

如何链接C库与Python在Windows下embedded?

Linux C ++用户空间应用程序实时hibernatefunction(POSIX,RaspBerry Pi)

Linux exec函数:arg0参数用于什么?

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐