有时我看到有人编译这样一个C程序:我是否需要在C程序中编译头文件?
gcc -o hello hello.c hello.h
据我所知,我们只是需要把头文件到C程序,如:
#include "somefile"
和编译C程序:gcc -o hello hello.c
。
我们什么时候需要编译头文件或者为什么?
有时我看到有人编译这样一个C程序:我是否需要在C程序中编译头文件?
gcc -o hello hello.c hello.h
据我所知,我们只是需要把头文件到C程序,如:
#include "somefile"
和编译C程序:gcc -o hello hello.c
。
我们什么时候需要编译头文件或者为什么?
首先,在一般:
如果这些.h
文件确实是典型的C风格的头文件(而不是作为完全不同的东西,只是碰巧与.h
扩展名来命名),则没有,我们没有理由以独立地“编译”这些头文件。头文件旨在包含在实现文件中,而不是作为独立的翻译单元提供给编译器。
由于典型的头文件通常只包含可以在每个翻译单元中安全地重复的声明,所以“编译”头文件完全没有不良后果。但同时它不会实现任何有用的功能。
基本上,编译hello.h
作为一个独立的翻译单元等效于创建一个简并dummy.c
文件仅由#include "hello.h"
指令,和喂养dummy.c
文件给编译器。它会编译,但它没有任何意义。
其次,专为GCC:
许多编译器会将不同,这取决于文件扩展名的文件。当GCC作为命令行参数提供给编译器时,GCC对.h
扩展名的文件有特殊处理。 GCC不是将其视为常规翻译单元,而是为该.h
文件创建一个预编译头文件文件。
你可以阅读一下:http://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
所以,这是你可能会看到.h
文件被直接输送到海湾合作委员会的原因。
好吧,让我们来了解主动和被动代码之间的区别。
活动代码是函数,过程,方法的实现,即应编译为可执行机器代码的代码段。我们将它存储在.c文件中,并确定我们需要编译它。
被动代码没有被执行本身,但它需要解释不同的模块如何相互通信。通常,.h文件只包含原型(函数头),结构。
宏是一个例外,它在形式上可以包含活动块,但您应该明白,它们正在使用简单替换构建(预处理)的最初阶段使用。在编译时,宏已经被替换为你的.c文件。
另一个例外是C++模板,应该在.h文件中实现。但是这里有一个类似于宏的故事:它们在早期阶段(实例化)和形式化上被替代,其他实例化是另一种类型。
总之,我认为,如果模块正确形成,我们不应该编译头文件。
我认为我们确实需要预处理(也许不会调用编译)头文件。因为根据我的理解,在编译阶段,头文件应该包含在c文件中。例如,在test.h我们有
typedef enum{
a,
b,
c
}test_t
和test.c的,我们在编译过程中有
void foo()
{
test_t test;
...
}
,我觉得编译器会放在头文件和C文件中的代码一起,头文件中的代码将被预处理并将代码替换为c文件中的代码。同时,我们最好在makefile中定义包含路径。
在某些系统中,尝试加速完全解析的'.c'文件的组装会调用预编译include文件“编译头文件”。然而,这是一种优化技术,对于实际的C开发来说不是必需的。
这样的技术基本上计算了包含语句并保留了扁平化包含的缓存。通常,C工具链将以递归方式剪切并粘贴包含的文件,然后将整个项目传递给编译器。使用预编译的头缓存,工具链将检查是否有任何输入(定义,头文件等)发生了变化。如果没有,那么它将提供已编排的文本文件片段给编译器。
这样的系统是为了加速开发;然而,许多这样的系统相当脆弱。随着计算机速度的加快以及源代码管理技术的改变,通用项目中实际使用的头文件预编译器数量更少。
直到您确实需要编译优化,我强烈建议您避免预编译头文件。
比方说,你还没有写hello.c,但你有头文件。然后你可以使用“gcc hello.h”来检查头文件的语法错误。否则,你必须创建一个包含hello.h的include语句的源文件(好吧,我想你无论如何都要这样做)。 – Mark