命令行与代码中的C宏定义

时间:2014-05-07 16:18:59

标签: c

考虑以下玩具程序(称之为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
        ^
  1. 命令行中的-DFOO和代码中的#define FOO之间有什么区别?
  2. 为什么命令行定义有效但内联定义会导致编译错误?
  3. 注意:我知道可以使用#ifdef和/或#define FOO 1解决此问题。这个问题的目的是请求解释,而不是解决方案

6 个答案:

答案 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

的POSIX标准所要求的
  

-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出现时,会导致FOO1替换,再次让替换后的行#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