我应该将包含在头文件还是源文件中?如果头文件包含include语句,那么如果我在源代码中包含该头文件,那么我的源文件是否包含我头文件中包含的所有文件?或者我应该只将它们包含在我的源文件中?
答案 0 :(得分:120)
如果标题本身需要,只将标题包括在标题中。
示例:
size_t
。然后在标题文件中#include <stddef.h>
。strlen
。然后在来源文件中#include <string.h>
。答案 1 :(得分:23)
这些年来,对此有很多不同意见。有一段时间,传统上只有标题声明与其相关的任何模块中的内容,因此许多标题具有您#include
a的特定要求某些标题集(按特定顺序)。一些非常传统的C程序员仍然遵循这种模式(至少在某些情况下,宗教上)。
最近,有一个让大多数标题独立的运动。如果该标题需要其他内容,则标题本身会处理该标题,确保包含所需内容(按正确顺序排列,如果存在排序问题)。就个人而言,我更喜欢这一点 - 特别是当标题的顺序很重要时,它只解决了一次问题,而不是要求每个使用它的人再次解决问题。
请注意,大多数标头只应包含声明。这意味着添加不必要的标头不应该(通常)对最终的可执行文件产生任何影响。最糟糕的情况是它会减慢编译速度。
答案 2 :(得分:11)
您的#include
应该是头文件,每个文件(源或标头)应该#include
它需要的头文件。头文件应该#include
必需的最小头文件,源文件也应该,尽管它对源文件不重要。
源文件的标题为#include
,标题为#include
,依此类推,直至最大嵌套深度。这就是为什么你不希望头文件中有多余的#include
:它们可能导致源文件包含许多它可能不需要的头文件,从而减慢了编译速度。
这意味着头文件完全可能被包含两次,这可能是个问题。传统方法是在头文件中加入“include guard”,例如文件foo.h:
#ifndef INCLUDE_FOO_H
#define INCLUDE_FOO_H
/* everything in header goes here */
#endif
答案 3 :(得分:4)
如果头文件A #includes
头文件B和C,则#includes
A的每个源文件也将获得B和C #included
。预处理器只是执行文本替换:在找到#include <foo.h>
的文本的任何地方,它都会将其替换为foo.h
文件的文本。
关于是否应将#includes
放在标头或源文件中,有不同的意见。就个人而言,我更喜欢在默认情况下将所有#includes
放在源文件中,但是任何没有其他先决条件标头都无法编译的头文件应该#include
这些标题本身。
每个头文件都应包含一个包含防护,以防止它被多次包含。
答案 4 :(得分:4)
我已经发展到二十多年的方法就是这样;
考虑一个图书馆。
有多个C文件,一个内部H文件和一个外部H文件。 C文件包含内部H文件。内部H文件包含外部H文件。
你从编译器POV中看到,因为它编译了一个C文件,所以有一个层次结构;
外部 - &gt;内部 - &gt; C代码
这是正确的排序,因为外部是第三方使用库所需的一切。编译C代码需要内部的。
答案 5 :(得分:4)
在某些环境中,如果仅包含所需的头文件,则编译速度最快。在其他环境中,如果所有源文件都可以使用相同的主要标头集合(某些文件可能具有超出公共子集的其他标头),则将优化编译。理想情况下,标头应该构造成多个#include操作不起作用。最好围绕#include语句,检查要包含的文件的include-guard,尽管这会对该保护的格式产生依赖性。此外,根据系统的文件缓存行为,一个不必要的#include,其目标最终完全#ifdef'ed可能不会花费很长时间。
另一件需要考虑的事情是,如果函数接受指向结构的指针,则可以将原型编写为
void foo(struct BAR_s *bar);
没有BAR_s的定义必须在范围内。一种非常方便的方法来避免不必要的包括。
PS - 在我的许多项目中,都会有一个文件,它预计每个模块都会#include,包含类似整数大小的typedef和一些常见的结构和联合[例如。typedef union { unsigned long l; unsigned short lw[2]; unsigned char lb[4]; } U_QUAD;
(是的,我知道如果我转向大端架构,我会遇到麻烦,但由于我的编译器不允许在联合中使用匿名结构,因此在联合中使用命名标识符将需要它们可以作为联盟.b.b1等访问,这似乎很烦人。
答案 6 :(得分:3)
制作所有文件,以便只使用它们包含的文件构建它们。如果您的标题中不需要包含,请将其删除。在一个大项目中,如果你不遵守这个规则,那么当有人从该文件的使用者使用的头文件中删除一个包含而不是标题时,你就会打开整个构建。
答案 7 :(得分:1)
如果您将源文件放在标头中,那么您的源文件将包含include语句。但是,在某些情况下,最好将它们放在源文件中。
请记住,如果您在任何其他来源中包含该标题,他们也会从标题中获取包含,并且这并不总是可取的。你应该只包括使用它的东西。
答案 8 :(得分:1)
您应该只在头部中包含声明常量和函数声明所需的文件。从技术上讲,这些包含也将包含在您的源文件中,但为了清楚起见,您应该只在每个文件中包含您实际需要使用的文件。你也应该在标题中保护他们免受多重包含:
#ifndef NAME_OF_HEADER_H
#define NAME_OF_HEADER_H
...definition of header file...
#endif
这可以防止多次包含标头,从而导致编译器错误。