为什么gcc在这个简单的测试程序中忽略这些头保护?
头文件是:
#ifndef MYHEADER_H
#define MYHEADER_H
#warning "header declared"
int some_int=0;
#endif
这两个.c文件是:main.c:
#include "header.h"
int main ()
{
return some_int;
}
来源:c:
#include "header.h"
int get_int()
{
return some_int;
}
使用编译时
gcc -o out main.c source.c
我得到以下输出:
In file included from main.c:1:
header.h:4:2: warning: #warning "header declared" [-Wcpp]
4 | #warning "header declared"
| ^~~~~~~
In file included from source.c:1:
header.h:4:2: warning: #warning "header declared" [-Wcpp]
4 | #warning "header declared"
| ^~~~~~~
/usr/bin/ld: /tmp/ccmAbN1J.o:(.bss+0x0): multiple definition of `some_int'; /tmp/ccEd5PwN.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
正如预期的那样,当编译器第一次包含头文件时,会显示警告。但是为什么头球后卫不阻止第二次入选呢?
gcc版本为:
gcc version 9.2.1 20200130 (Arch Linux 9.2.1+20200130-2)
Header保护防止在单个翻译单元中包含多个内容(通常是.c
文件及其直接或间接包含的所有内容(。
您有两个翻译单元,main.c
和source.c
,它们是独立编译的(即使使用单个命令行gcc main.c source.c
(。这就是为什么您从链接器而不是编译器获得错误消息的原因。
如果要定义对象,则应在.c
文件中进行定义,并在相应的.h
文件中将其声明为extern
。定义对象的.c
文件只编译一次,其他多个.c
文件可以在.h
文件中看到声明。
它不会忽略它们。您有两个独立的编译单元,每个单元都需要header.h
。标头保护旨在防止单个编译单元两次包含同一标头。例如如果main.c
包含header.h' directly, but also included
foo.h which also included
header.h , when all the includes are expanded the header guard ensures that
header.h的内容只出现一次。
有两个编译单元:1个用于main.c
,1个用于source.c
。这些文件由编译器单独(完全独立(编译,生成2个对象文件(例如main.o
和source.o
(。每个都会打印警告:
In file included from main.c:1:
header.h:4:2: warning: #warning "header declared" [-Wcpp]
4 | #warning "header declared"
| ^~~~~~~
然后,这些对象文件通过链接器链接到可执行的out
中。
但链接器发现两个对象文件定义了相同的符号some_int
,因此无法生成可执行文件,导致:
/usr/bin/ld: /tmp/ccmAbN1J.o:(.bss+0x0): multiple definition of `some_int'; /tmp/ccEd5PwN.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status