11

我遵循我编译的代码gcc

#include<stdio.h>
#include<stdbool.h>
#define true 9
int main() { 
   printf("TRUE = %d\n",true);
   return 0;
}

我得到错误

test.c:3:0: warning: "true" redefined [enabled by default]
In file included from test.c:2:0:
/usr/lib/gcc/x86_64-linux-gnu/4.7/include/stdbool.h:34:0: note: this is the location of the previous definition

但是当我稍微改变代码时

#include<stdio.h>
#define true 9
#include<stdbool.h>
int main() { 
   printf("TRUE = %d\n",true);
   return 0;
}

输出:

TRUE = 1

问题:

我理解第一种情况下出错的原因,但在第二种情况下,当我在我true之前定义时#include<stdbool.h>,为什么允许重新定义true

更新:

这是stdbool.h

前几行是

#ifndef _STDBOOL_H
#define _STDBOOL_H

#ifndef __cplusplus

#define bool    _Bool
#define true    1
#define false   0

这一点不像于浩的回答

4

3 回答 3

9

在文件stdbool.h中,代码可能如下所示:

#ifdef true
#undef true
#define true 1
#endif

如果之前定义了宏,您也应该这样做。另一个类似的技巧是这样的:

#ifndef MAGIC
#define MAGIC 42
#endif

编辑

原来这是gcc 的功能,请参阅@alk 的答案以了解详细信息。

在 GCC 处理系统标头时,所有警告(由“#warning”生成的警告除外)都将被抑制。系统标头中定义的宏在扩展时不受一些警告的影响。

于 2013-09-23T11:36:03.340 回答
7

余皓虽然给出了一个可能的答案,但这里的情况确实不同。

这可以很容易地通过研究来证明,在 的定义周围stdbool.h没有#ifdef ... #endif“警卫” true

此外,gcc 确实简单地抑制了应针对系统标头*1中的问题给出的警告。

使用 gcc 的选项-isystem使第一个示例的行为类似于第二个示例。

从 gcc 手册:

声明操作系统和运行时库接口的头文件通常不能用严格符合的 C 语言编写。因此,GCC 对系统头文件中的代码进行特殊处理。在 GCC 处理系统标头时,所有警告,除了由 '#warning' 生成的警告(请参阅诊断)之外,都会被抑制。系统标头中定义的宏在扩展时不受一些警告的影响。当我们发现由于系统头文件中定义的宏中的代码而导致警告产生大量误报时,这种豁免权是临时授予的。

[...]

-isystem 命令行选项将其参数添加到目录列表中以搜索标题,就像 -I 一样。在该目录中找到的任何标头都将被视为系统标头。


*1: 系统标题是包含在<>括号中的标题。

于 2013-09-23T12:28:55.970 回答
-1

好吧,您的警告已经说明了:

test.c:3:0: warning: "true" redefined [enabled by default]

GCC 允许您重新定义值,除非您明确告诉它不要这样做。您可以为此使用 -Werror。

于 2013-09-23T12:27:26.263 回答