命令行上的C宏定义与代码中的宏定义
考虑下面的玩具程序(称之为命令行上的C宏定义与代码中的宏定义,c,C,考虑下面的玩具程序(称之为Foo.c),并注意到#define Foo已被注释掉 #include <stdio.h> // #define FOO int main(){ #if FOO printf("Foo\n"); #else printf("Bar\n"); #endif } 但是,如果我们取消注释行#define FOO,并使用gcc-o FOO FOO.c进行编译,则会生成编译器错误 Foo.c:5:8: error: #if with no exp
Foo.c
),并注意到#define Foo
已被注释掉
#include <stdio.h>
// #define FOO
int main(){
#if FOO
printf("Foo\n");
#else
printf("Bar\n");
#endif
}
但是,如果我们取消注释行#define FOO
,并使用gcc-o FOO FOO.c
进行编译,则会生成编译器错误
Foo.c:5:8: error: #if with no expression
#if FOO
^
-DFOO
与代码中的#define FOO
有什么区别\ifdef
和/或\define FOO 1
纠正。此问题的目的是要求解释,而不是解决问题。使用#ifdef而不是#if检查宏是否已定义。否则,您可以将宏更改为#define FOO 0或#define FOO 1以启用/禁用代码
例如:
#include <stdio.h>
// #define FOO
int main(){
#ifdef FOO
printf("Foo\n");
#else
printf("Bar\n");
#endif
}
#包括
//#定义FOO
int main(){
#ifdef FOO
printf(“Foo\n”);
#否则
printf(“Bar\n”);
#恩迪夫
}
在GCC命令行中,-DFOO
是-DFOO=1
的缩写。证明:
#include <stdio.h>
// #define FOO
int main(){
#if FOO
printf("Foo %d\n", FOO);
#else
printf("Bar %d\n", FOO);
#endif
}
这实际上是POSIX标准的要求
-D name[=value]
通过C语言
#Define
指令定义名称。如果未给出=值
,则应使用值1。-D
选项的优先级低于-U
选项。也就是说,如果在-U
和-D
选项中都使用了名称
,则无论选项的顺序如何,名称
都应是未定义的
因此,它基本上可以在任何地方工作。线路
#define FOO
表示将FOO
预处理为空字符串。
行#if FOO
变为#if
,这当然是一个语法错误,错误消息“#if with no expression”表明了这一点
当命令行上不存在-DFOO
时,FOO
不被定义为任何东西,因此#if FOO
行仍然是#if FOO
在预处理的替换阶段之后(未明确定义的FOO
等符号在#if
条件内计算为0
). 当出现-DFOO
时,它会使FOO
替换为1
,如果替换后FOO在语法上有效,则再次保留行
命令行选项-DFOO
的等效定义是\define FOO 1
根据C99的6.10.1p3,定义FOO的等效命令行选项是-DFOO=
(谈论“if”和“elif”):
由于宏扩展和定义的一元运算符而进行的所有替换完成后,所有剩余的标识符将替换为pp编号0,然后每个预处理令牌将转换为令牌
因此,FOO
,如果未定义,则根据此规则变成文本0
,如果FOO
没有给出错误,则变成。但是,当您定义FOO时,它会扩展为零(正如您定义的那样),并且您会得到一个错误
GCC的-DFOO
的行为与您期望的不完全一样(比如#define FOO
)-它给它一个默认值1
。(编辑:显然这是POSIX强制要求的…,请参见Jonathan Leffler的回答。)当编译一个C程序时,C编译器会多次遍历您的代码。第一个过程称为预处理器扩展阶段#define
的工作原理非常类似于文字处理器的复制和粘贴。当编译器到达这一行时:
#define FOO
#if FOO
编译器像内部字典一样保存名称和值。它接受FOO
(名称)并在字典中将其与其后的任何文本(值)相关联。在本例中,后面没有值,因此将存储一个空字符串作为值
当编译器到达这一行时:
#define FOO
#if FOO
编译器在其字典中查找名称FOO
,并说“嗯,我的字典中有一个名为FOO
”的名称。如果没有,则会发生错误。不过,在本例中,字典中有一个FOO
名称,它用与其相关联的任何值(空字符串)替换名称FOO
。所以这条线变成了这样:
#if
编译器完成预处理器扩展阶段后,将再次运行代码,执行预处理器指令(如#if
)。当它到达扩展的#if
行时,它无效,因为#if
后面没有任何内容,编译器不知道如何处理它
为了使代码有效,有两个修复程序。一种是这样定义你的FOO
:
#define FOO 1
#if 1
通过这样做,预处理器扩展阶段会将行扩展为如下所示:
#define FOO 1
#if 1
因为C中的1
被解释为true,所以它可以很好地编译
第二种修复方法是将#if
更改为#ifdef
#ifdef
是一个预处理器指令,如果定义了FOO
,则该指令的计算结果为true。它的定义与此无关。无论值是多少,它都将返回true。#如果期望表达式,而Foo不是表达式。
看看这个例子
在您的情况下,必须使用#ifdef和#ifndef我的问题不是如何修复它。我的问题是为什么观察到的行为会发生。这是唯一真正解决我问题的答案!将在几分钟内接受,但如果您手头有一份简写文档参考,也将不胜感激。这将解决问题的一半,但不能解决问题的另一半,这就是为什么-DFOO
工作正常的原因。@merlin2011我正忙着撰写您的评论。具体来说,我正忙于使用gcc-C-E test.C检查事实