考虑以下玩具程序(称之为Foo.c
),并观察#define FOO
已被注释掉。
#include <stdio.h>
// #define FOO
int main(){
#if FOO
printf("Foo\n");
#else
printf("Bar\n");
#endif
}
使用以下两个命令行编译好。
gcc -o Foo Foo.c
gcc -DFOO -o Foo Foo.c
但是,如果我们取消注释行#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
解决此问题。这个问题的目的是请求解释,而不是解决方案。
答案 0 :(得分:3)
在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
}
现在只能使用-DFOO
(或使用显式值-DFOO=-32768
或使用#define FOO 1
或类似内容)进行编译。
$ gcc -o md -DFOO md.c && ./md
Foo 1
$
这实际上是c99
-D name[=value]
使用C语言#define
指令定义名称。如果没有给出=value
,则应使用值1。-D
选项的优先级低于-U
选项。也就是说,如果在name
和-U
选项中同时使用-D
,则无论选项的顺序如何,name
都将是未定义的。
因此它基本上可以在任何地方使用。
答案 1 :(得分:2)
使用#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
}
答案 2 :(得分:1)
该行
#define FOO
表示FOO
被预处理为空字符串。
行#if FOO
变为#if
,这当然是语法错误,正如错误消息“#if with no expression”所示。
当命令行中没有-DFOO
时,FOO
未被定义为任何内容,因此在预先替换阶段之后,行#if FOO
仍为#if FOO
处理(未明确定义的FOO
之类的符号在0
条件内评估为#if
。当-DFOO
出现时,会导致FOO
被1
替换,再次让替换后的行#if FOO
在语法上有效。
命令行选项#define
的等效-DFOO
定义为#define FOO 1
。
#define FOO
的等效命令行选项为-DFOO=
答案 3 :(得分:0)
根据C99的6.10.1p3(谈论#if和#elif):
在由于宏扩展和已定义的一元运算符执行的所有替换之后,所有剩余的标识符都替换为pp-number 0,然后每个预处理标记都转换为标记。
因此,FOO
,未定义时,按此规则成为文字0
,#if FOO
不会给您一个错误。但是,当您#define FOO
时,它会扩展为任何内容(正如您所定义的那样)并且您会收到错误。
海湾合作委员会-DFOO
的行为并不像你期望的那样(如#define FOO
) - 它的默认值为1
。 (编辑:显然这是POSIX强制要求......,请参阅Jonathan Leffler的回答。)
答案 4 :(得分:0)
编译C程序时,C编译器会多次遍历您的代码。第一次传递称为预处理器扩展阶段。 #define
非常类似于文字处理程序的复制和粘贴。当编译器出现在这一行时:
#define FOO
编译器像名称和值的内部字典一样保留。它需要FOO
(名称)并将其与字典中的任何文本(值)相关联。在这种情况下,之后没有值,因此将空字符串存储为值。
编译器到达此行时:
#if FOO
编译器在其字典中查找名称FOO
,并说“我的字典中有一个名为FOO
的名称”。如果没有,则发生错误。但在这种情况下,字典中有一个FOO
名称,它将名称FOO
替换为与其关联的任何值(空字符串)。所以这条线就变成了这个:
#if
编译器完成预处理器扩展阶段后,它会再次运行代码,执行预处理器指令(例如#if
)。当它到达扩展的#if
行时,它无效,因为#if
之后没有任何内容,编译器不知道如何处理它。
为了使您的代码有效,有2个修复程序。一种是定义你的FOO
:
#define FOO 1
通过这样做,预处理器扩展阶段会将该行扩展为如下所示:
#if 1
由于C中的1
被解释为true,因此编译就好了。
解决此问题的第二种方法是将#if
更改为#ifdef
。 #ifdef
是一个预处理程序指令,如果定义了FOO
,则该指令的计算结果为true。它的定义是无关紧要的。无论价值如何,它都会返回true。
答案 5 :(得分:0)
#if 期待表达式,而Foo不是表达式。 看一下这个例子http://msdn.microsoft.com/en-us/library/4y6tbswk.aspx
在您的情况下,您必须使用 #ifdef &amp; 的#ifndef