在哪里放置包含语句、标题或来源?
Posted
技术标签:
【中文标题】在哪里放置包含语句、标题或来源?【英文标题】:Where to put include statements, header or source? 【发布时间】:2011-04-25 23:51:43 【问题描述】:我应该将包含在头文件中还是源文件中?如果头文件包含包含语句,那么如果我在源代码中包含该头文件,那么我的源文件是否会包含头文件中的所有包含文件?还是应该只将它们包含在我的源文件中?
【问题讨论】:
许多以前在 SO 上的重复,例如where should "include" be put in C++ Should I use #include in headers?的可能重复 【参考方案1】:在某些环境中,如果只包含自己需要的头文件,编译会最快。在其他环境中,如果所有源文件都可以使用相同的主要标头集合(某些文件可能具有超出公共子集的附加标头),则编译将得到优化。理想情况下,应该构造标头,以便多个#include 操作无效。用检查要包含的文件的 include-guard 来围绕 #include 语句可能会很好,尽管这会产生对该保护格式的依赖。此外,根据系统的文件缓存行为,一个不必要的#include,其目标最终被完全#ifdef'ed 删除可能不会花费很长时间。
要考虑的另一件事是,如果一个函数接受一个指向结构的指针,则可以将原型写为
void foo(struct BAR_s *bar);没有 BAR_s 的定义必须在范围内。避免不必要的包含的一种非常方便的方法。
PS——在我的许多项目中,都会有一个文件,预计每个模块都会#include,其中包含诸如整数大小的 typedef 和一些常见的结构和联合 [例如
typedef联合 无符号长 l; 无符号短lw[2]; 无符号字符磅[4]; U_QUAD;(是的,我知道如果我迁移到大端架构会遇到麻烦,但是由于我的编译器不允许在联合中使用匿名结构,因此对联合中的字节使用命名标识符将需要它们以 theUnion.b.b1 等方式访问,这似乎很烦人。
【讨论】:
【参考方案2】:我二十多年演变成的方法是这样的;
考虑一个库。
有多个C文件,一个内部H文件和一个外部H文件。 C 文件包括内部 H 文件。内部H文件包含外部H文件。
您从编译器 POV 中看到,当它编译 C 文件时,有一个层次结构;
外部 -> 内部 -> C 代码
这是正确的顺序,因为外部是第三方使用库所需的一切。编译 C 代码需要内部的。
【讨论】:
【参考方案3】:仅当标头本身需要时才将包含内容放入标头中。
例子:
您的函数返回类型size_t
。然后在 header 文件中#include <stddef.h>
。
您的函数使用strlen
。然后在 source 文件中#include <string.h>
。
【讨论】:
如果我的函数接受size_t
类型的参数怎么办?
同样的问题扩展到 c++:如果我的结构/类有一个类型为 size_t
或 std::string
的字段/成员怎么办?
原理是什么?
我有一个有线情况,C++ 类 A 有另一个 B 类的对象,我不能使用 B 的前向声明和最终在 A 标头中包含 B 标头。 (使用指针没有这个问题)
@andrybak 您的源文件应该包含您的头文件,因此任何包含您的头文件的内容都会得到您的源文件。【参考方案4】:
制作所有文件,以便仅使用它们包含的内容来构建它们。如果您不需要包含在标题中,请将其删除。在一个大项目中,如果您不遵守这一原则,那么当有人从该文件的使用者甚至不被该头文件使用的头文件中删除包含时,您就会让自己破坏整个构建。
【讨论】:
【参考方案5】:你应该只在你的头文件中包含你需要声明常量和函数声明的文件。从技术上讲,这些包含也将包含在您的源文件中,但为了清楚起见,您应该只在每个文件中包含您实际需要使用的文件。因此,您还应该保护它们在您的标头中免受多次包含:
#ifndef NAME_OF_HEADER_H
#define NAME_OF_HEADER_H
...definition of header file...
#endif
这样可以防止标头被多次包含,从而导致编译器错误。
【讨论】:
【参考方案6】:多年来,对此存在很多分歧。曾几何时,标头only 声明与其相关的任何模块中的内容是传统的,因此 许多 标头有特定的要求,即您 #include
某个集合标题(按特定顺序)。一些极其传统的 C 程序员仍然遵循这种模式(至少在某些情况下是宗教上的)。
最近,出现了使大多数标题独立的趋势。如果该标头需要其他内容,则标头本身会处理该问题,以确保包含所需的任何内容(如果存在排序问题,则以正确的顺序排列)。就我个人而言,我更喜欢这个——尤其是当标题的顺序很重要时,它解决了一次问题,而不是要求每个使用它的人再次解决问题。
请注意,大多数标题应该只包含声明。这意味着添加不必要的标头不应该(通常)对您的最终可执行文件产生任何影响。最糟糕的情况是它会稍微减慢编译速度。
【讨论】:
如果所有标题都以第二种样式编写,则根本不存在排序问题。标题中的排序问题通常意味着您没有在标题中包含您需要的所有内容。【参考方案7】:你的#include
s 应该是头文件,每个文件(源或头)应该#include
它需要的头文件。头文件应该#include
所需的最小头文件,源文件也应该,尽管它对源文件没有那么重要。
源文件的标题为#include
s,标题为#include
,依此类推,直到最大嵌套深度。这就是为什么您不希望在头文件中出现多余的#include
s:它们会导致源文件包含许多它可能不需要的头文件,从而减慢编译速度。
这意味着头文件完全有可能被包含两次,这可能是个问题。传统的方法是把“include guards”放在头文件中,比如文件foo.h:
#ifndef INCLUDE_FOO_H
#define INCLUDE_FOO_H
/* everything in header goes here */
#endif
【讨论】:
我知道这个答案已经过时了,但是从那以后他们添加了 #pragma 一次,所以你不要在声明 #includes 时包含 #ifndef 我发布了这个因为较旧但更受欢迎/赞成的线程往往成为谷歌搜索的顶部【参考方案8】:如果头文件 A #includes
头文件 B 和 C,那么每个 #includes
A 的源文件也会得到 B 和 C #included
。预处理器实际上只是执行文本替换:在任何它找到显示#include <foo.h>
的文本的地方,它都会将其替换为foo.h
文件的文本。
对于是否应该将#includes
放在头文件或源文件中存在不同的意见。就个人而言,我更喜欢默认将所有#includes
放在源文件中,但是任何没有其他先决条件头文件就无法编译的头文件应该#include
这些头文件本身。
并且每个头文件都应该包含一个包含保护,以防止它被多次包含。
【讨论】:
【参考方案9】:如果你把它放在标题中,你的源文件将包含包含语句。但是,在某些情况下,最好将它们放在源文件中。
请记住,如果您在任何其他来源中包含该标头,它们也会从标头中获取包含,但这并不总是可取的。你应该只包括使用它的东西。
【讨论】:
以上是关于在哪里放置包含语句、标题或来源?的主要内容,如果未能解决你的问题,请参考以下文章