我需要在C程序中编译头文件吗?
有时候我看到有人编译一个像这样的C程序:
gcc -o hello hello.c hello.h
据我所知,我们只需要把头文件放到C程序中就好:
#include "somefile"
并编译C程序: gcc -o hello hello.c
。
我们什么时候需要编译头文件或者为什么?
首先,一般来说:
如果这些.h
文件确实是典型的C风格的头文件(而不是完全不同的东西,恰好用.h
扩展名来命名),那么没有,没有理由独立地“编译”这些头文件。 头文件旨在包含在实现文件中,而不是作为独立的翻译单元提供给编译器。
由于典型的头文件通常只包含可以在每个翻译单元中安全地重复的声明,所以“编译”头文件是完全可以预料的,不会产生有害的后果。 但同时它不会达到任何有用的。
基本上,编译hello.h
是一个独立的翻译单元,相当于创build一个仅包含#include "hello.h"
指令的退化dummy.c
文件,并将该dummy.c
文件提供给编译器。 它会编译,但是没有意义。
其次,特别是对于GCC:
许多编译器会根据文件扩展名对待不同的文件。 当GCC作为命令行参数提供给编译器时,GCC对扩展名为.h
文件有特殊的处理。 GCC不是将其视为常规翻译单元,而是为该.h
文件创build一个预编译头文件。
你可以在这里阅读: http : //gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
所以,这就是你可能会看到.h
文件被直接送到GCC的原因。
好的,让我们来了解主动和被动代码之间的区别。
活动代码是函数,过程,方法的实现,即应编译为可执行机器代码的代码段。 我们将它存储在.c文件中,并确定我们需要编译它。
被动代码并不是自己执行,而是需要解释不同的模块如何相互通信。 通常,.h文件仅包含原型(函数头),结构。
macros是一个例外,它可以包含一个活动块,但是你应该明白,他们正在使用简单replace的构build(预处理)的早期阶段。 在编译时,macros已经被replace为你的.c文件。
另一个例外是C ++模板,应该在.h文件中实现。 但是这里有一个类似于macros的例子:在早期阶段(实例化)和forms化阶段被replace,其他实例化是另一种types。
总之,我认为,如果模块正确形成,我们不应该编译头文件。
我认为我们需要预处理(也许不会调用编译)头文件。 因为从我的理解来看,在编译阶段,头文件应该包含在c文件中。 例如,在test.h中我们有
typedef enum{ a, b, c }test_t
在test.c中我们有
void foo() { test_t test; ... }
在编译期间,我认为编译器会把代码放在head文件和c文件中,头文件中的代码将被预处理,并用c文件替代代码。 同时,我们最好在makefile中定义包含path。
在某些系统中,尝试加快完全parsing的“.c”文件的汇编,将调用包含文件“编译头文件”的预先汇编。 但是,对于实际的C开发来说,这是一种优化技术。
这样的技术基本上计算了包含语句,并且保留了展开包含的caching。 通常情况下,C工具链将以recursion方式剪切和粘贴包含的文件,然后将整个项目传递给编译器。 使用预编译头caching,工具链将检查是否有任何input(定义,头等)已经改变。 如果不是,那么它会提供已经拼合的文本文件片段给编译器。
这样的制度是为了加快发展; 然而,许多这样的系统相当脆弱。 随着计算机速度的加快以及源代码pipe理技术的改变,在普通项目中实际使用的头文件预编译器就会less得多。
在实际需要编译优化之前,我强烈build议您避免预编译头文件。