整个源文件中的头文件是否重复?

时间:2012-04-23 10:06:16

标签: c gcc c99

// File foo1.c :
#include <stdio.h> // once
void foo1(void);
void foo1(void){
    puts("foo1");
}

// File foo2.c :
#include <stdio.h> // again
void foo2(void);
void foo2(void){
    puts("foo2");
}

// File foomain.c :
#include <stdio.h> // yet again
void foo1(void); // again
void foo2(void); // again
int main(void){
    foo1();
    foo2();
    puts("foomain");
    return 0;
}

// create object files
gcc -fPIC foo1.c -o foo1.o // 1 stdio.h
gcc -fPIC foo2.c -o foo2.o // 1 stdio.h

// create shared library
gcc -fPIC -shared foo1.o foo2.o -o foo.so // foo.so contains stdio.h 2 times ?

// build entire program
gcc foo.so foomain.c -o foomain // foomain contains 1 stdio.h plus the 2 from foo.so ?
  1. 为什么整个程序包含3个stdio.h?似乎多余,为什么不只是1?编译器不应该只需要1吗?

  2. 对象文件包含原型是有意义的,但为什么必须在foomain.c中再次指定它们?编译器是否应该知道它们已经在foo.so中指定了?

4 个答案:

答案 0 :(得分:6)

那是因为每个文件都是单独编译的,所以每次编译器都应该知道用于执行编译时检查的所有函数的签名。因此,每个文件都必须包含所有使用的声明,这些声明在编译文件之前由预处理器包含。

答案 1 :(得分:2)

如果你看一下大多数头文件的顶部,他们就有一个包含守卫来阻止双重包含。

#ifndef FOO
#define FOO

#endif

有关详细信息,请参阅Include Guard

答案 2 :(得分:1)

#include行实际上不是编译器的一部分,而是C preprocessor

预处理器对#include行的作用是将文件实际包含到源中,并创建一个包含文件内容的新临时文件,其中#include行替换为文件被包含在内。

如果你所做的只是调用函数,你根本不需要包含文件。您可能会收到有关未声明的函数的警告,但可以自行添加这些函数的原型。例如,在您的主要源文件中,您只使用puts,而不是包含<stdio.h>,您可以添加如下原型:

int puts(const char *s);

但是,<stdio.h>还定义了一些结构(如FILE结构)并声明了一些变量(如stdout),如果你使用其中任何一个,你也需要头文件

答案 3 :(得分:0)

你可以使用@Jeff建议的包含警戒,或者只将#pragma once放在每个标题的顶部。