包含from include文件的最佳实践

Best practice for including from include files

本文关键字:最佳 文件 from include 包含      更新时间:2023-10-16

我想知道在包含文件中直接包含语句是否有一些利弊,而不是在源文件中包含它们。

我个人喜欢有我的包含"干净",所以,当我在一些c/cpp文件中包含它们时,我不必寻找每一个可能的头,因为包含文件不照顾它自己。另一方面,如果我在包含文件中包含了包含,编译时间可能会变大,因为即使有包含保护,也必须首先解析文件。这仅仅是品味的问题,还是两者之间有优劣之分?

我的意思是:

sample.h

#ifdef ...
#include "my_needed_file.h"
#include ...
class myclass
{
}
#endif

sample.c

#include "sample.h"
my code goes here

sample.h

#ifdef ...
class myclass
{
}
#endif

sample.c

#include "my_needed_file.h"
#include ...
#include "sample.h"
my code goes here

实际上没有任何标准的最佳实践,但对于大多数帐户,您应该在头文件中包含您真正需要的内容,并向前声明您可以的内容。

如果一个实现文件需要一些头文件没有明确要求的东西,那么这个实现文件应该包含它自己。

该语言没有要求,但几乎是通用的公认的编码规则是所有标头必须是self足够的;由单个语句组成的源文件包含include的编译应该没有错误。通常的验证这一点的方法是在实现文件中包含它的头在其他任何东西之前。

编译器只需要读取每个include一次。可以确定它已经读取了文件,在读取它时,它检测到包含保护模式,它有不需要重新读取文件;它只是检查控制是否预处理器令牌是(仍然)定义的。(有编译器无法检测到的配置所包含的文件是否与先前包含的文件相同文件。在这种情况下,它必须再次读取文件,并且重新解析。然而,这种情况相当罕见)

头文件应该被视为API。假设你正在为客户端编写一个库,你将为他们提供一个头文件用于包含在他们的代码中,以及一个编译后的二进制库用于链接。

在这种情况下,在你的头文件中添加一个"#include"指令会给你的客户和你带来很多问题,因为现在你必须提供不必要的头文件来编译东西。尽可能多的前向声明使API更清晰。如果你的客户端想要的话,它还允许你的客户端在你的头文件上实现他们自己的函数。

如果你确信你的头永远不会在你当前的项目之外使用,那么任何一种方式都不是问题。如果您使用包含保护,编译时间也不是问题,您本来就应该使用这些保护。

在头文件中包含更多的(不需要的)符号意味着在接口级别有更多的(不需要的)符号可见。这可能会造成很多混乱,可能会导致符号冲突和臃肿的界面

另一方面,如果我在include文件中包含了include,编译时间可能会变大,因为即使有include保护

如果你的编译器不记得哪些文件有include守卫,避免重新打开和重新标记文件,然后得到一个更好的编译器。大多数现代编译器已经这样做很多年了,所以多次包含同一个文件是没有成本的(只要它包含了include守卫)。参见http://gcc.gnu.org/onlinedocs/cpp/Once_002dOnly-Headers.html

头文件应该是自给自足的,并且包含/声明它们需要的内容。期望头文件的用户包含它的依赖项是不好的做法,也是让用户讨厌你的好方法。

如果my_needed_file.hsample.h之前需要(因为sample.h需要它的声明/定义),那么它应该包含在sample.h中,毫无疑问。如果sample.h中不需要,只在sample.c中需要,那么只在那里包含它,我的偏好是在 sample.h之后包含它,这样如果sample.h 缺少它需要的任何头,那么你会更快地知道它:

// sample.c
#include "sample.h"
#include "my_needed_file.h"
#include ...
#include <std_header>
// ...

如果您使用这个#include顺序,那么它会迫使您使sample.h自给自足,这确保您不会给标题的其他用户带来问题和烦恼。

我认为第二种方法更好,原因如下:

  1. 当你的头文件中有一个函数模板时

    class myclass
    {
        template<class T>
        void method(T& a)
        {
           ...
        }
    }
    

并且您不想在myclass.cxx的源文件中使用它。但是你想在xyz中使用它。Cxx,如果你采用第一种方法,那么你最终会包括myclass所需的所有文件。Cxx,它对xyz.cxx没有用处。

这就是我现在所认为的区别。因此,我认为应该采用第二种方法,因为它使您的代码在将来易于维护。