有时我看到有人编译这样的C程序:
gcc -o hello hello.c hello.h
据我所知,我们只需要将头文件放入C程序中,如:
#include "somefile"
编译C程序:gcc -o hello hello.c
。
我们什么时候需要编译头文件?为什么?
答案 0 :(得分:29)
首先,一般来说:
如果这些.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
个文件直接送到GCC的原因。
答案 1 :(得分:5)
好的,让我们理解主动代码和被动代码之间的区别。
活动代码是函数,过程,方法的实现,即应编译为可执行机器代码的代码片段。我们将它存储在.c文件中,确定我们需要编译它。
被动代码本身并不是执行,但它需要解释不同模块如何相互通信。通常,.h文件只包含原型(函数头),结构。
一个例外是宏,它正式可以包含一个活动的部分,但你应该理解它们是在构建(预处理)的早期阶段使用简单的替换。在编译时,宏已经被替换为.c文件。
另一个例外是C ++模板,应该在.h文件中实现。但是这里的故事类似于宏:它们在早期阶段(实例化)被替换,并且正式地,彼此实例化是另一种类型。
总之,我认为,如果模块形成正确,我们就不应该编译头文件。
答案 2 :(得分:2)
当我们像这样包含头文件时:#include
答案 3 :(得分:1)
我认为我们确实需要预处理(可能不会调用编译)头文件。因为根据我的理解,在编译阶段,头文件应该包含在c文件中。例如,在test.h中我们有
typedef enum{
a,
b,
c
}test_t
在test.c中我们有
void foo()
{
test_t test;
...
}
在编译期间,我认为编译器会将代码放在头文件和c文件中,头文件中的代码将被预处理并替换c文件中的代码。同时,我们最好在makefile中定义包含路径。
答案 4 :(得分:1)
在某些系统中,尝试加速完全解析的“.c”文件的组装会调用包含文件“编译头文件”的预先组装。但是,这是一种优化技术,对于实际的C开发来说并不是必需的。
这种技术基本上计算了include语句并保留了flattened包含的缓存。通常,C工具链将递归地剪切并粘贴包含的文件,然后将整个项目传递给编译器。使用预编译的头缓存,工具链将检查是否有任何输入(定义,标题等)已更改。如果没有,那么它将向编译器提供已经扁平化的文本文件片段。
此类系统旨在加快发展;然而,许多这样的系统非常脆弱。随着计算机加速,源代码管理技术发生变化,在公共项目中实际使用的标头预编译器更少。
在您真正需要编译优化之前,我强烈建议您避免预编译标题。
答案 5 :(得分:0)
您不需要编译头文件。它实际上什么也没做,因此尝试运行它毫无意义。但是,这是检查拼写错误,错误和错误的好方法,因此以后会更容易。