好C头样式

Phi*_*lip 9 c coding-style header-files

我的C标头通常类似于以下样式,以避免多重包含:

#ifndef <FILENAME>_H
#define <FILENAME>_H

// define public data structures / prototypes, macros etc.

#endif  /* !<FILENAME>_H */
Run Code Online (Sandbox Code Playgroud)

但是,在他的C语言编程中,Rob Pike对头文件做了如下论证:

有一个小小的舞蹈涉及#ifdef到可以防止文件被读取两次,但它在实践中通常是错误的 - #ifdef它们在文件本身,而不是包含它的文件.结果往往是成千上万的不必要的代码行通过词法分析器,这是(在良好的编译器中)最昂贵的阶段.

一方面,派克是我唯一真正钦佩的程序员.另一方面,将多个#ifdefs放在多个源文件中而不是将其#ifdef放在单个头文件中会感到不必要的尴尬.

处理多重包含问题的最佳方法是什么?

Mar*_*ins 11

在我看来,使用需要较少时间的方法(这可能意味着将#ifdefs放在头文件中).如果我的结果代码更清晰,编译器必须更加努力,我真的不介意.或许,如果您正在开发一个数百万行代码库,而您经常需要完全重建,那么额外的节省可能是值得的.但在大多数情况下,我怀疑额外费用通常并不明显.

  • 我发现这个答案非常有用.有趣的是,我以更具讽刺意味的方式表示同意:如果计算机可以完成我的工作,为什么我会这样做呢?;) (2认同)

Eri*_*rik 6

继续做你做的事情 - 它很清楚,不易出错,并且编译器编写者都知道,所以不像十年或两年前那样低效.

你可以使用非标准#pragma once- 如果你搜索,一旦讨论,可能至少有一个书架的价值包括警卫和编译,所以我不会推荐一个而不是另一个.

  • @R ..:它声称这样做 - http://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html。然而,它使用一些限制来确保优化是有效的,并且在限制被破坏的情况下可能会出现漏报,但在这种情况下优化仍然有效。 (2认同)

use*_*610 5

Pike 在https://talks.golang.org/2012/splash.article中写了更多相关内容

\n\n
\n

1984 年,ps.c人们观察到对 Unix ps 命令源代码的编译\n#include <sys/stat.h>当所有预处理完成时尽管这样做时内容会被丢弃 36 次,但大多数 C 实现都会打开文件、读取文件并扫描 37 次。事实上,如果没有很高的技巧,这种行为就是 C 预处理器潜在复杂的宏语义所需要的。

\n
\n\n

从那时起,编译器变得非常聪明:https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html,所以现在这不再是一个问题。

\n\n
\n

Google 构建的单个 C++ 二进制文件可以打开和读取数百个单独的头文件数万次。2007 年,Google 的构建工程师对主要 Google 二进制文件的编译进行了检测。该文件包含大约 2000 个文件,\n 如果简单地连接在一起,总计 4.2 兆字节。当 #include 扩展时,超过 8 GB 的数据被传送到编译器的输入,每个 C++ 源字节增加了 2000 个字节。

\n\n

作为另一个数据点,2003 年,Google 的构建系统从单个 Makefile 转移到了按目录设计,具有更好的管理、更显式的依赖关系。仅仅因为记录了更准确的依赖关系,典型的二进制文件的文件大小就缩小了约 40%。即便如此,\n C++(或就此而言的 C)的属性使得自动验证\n 这些依赖关系变得不切实际,并且今天我们仍然没有\n 准确了解大型 Google\n C++ 二进制文件的依赖关系要求。

\n
\n\n

关于二进制大小的观点仍然相关。编译器(链接器)对于剥离未使用的符号非常保守。如何使用 GCC 和 ld 删除未使用的 C/C++ 符号?

\n\n
\n

在计划 9 中,头文件被禁止包含进一步的 #include子句;所有#includes内容都必须位于顶级 C 文件中。这需要一些纪律,当然\xe2\x80\x94程序员需要\n以正确的顺序列出一次必要的依赖关系\xe2\x80\x94但是文档有所帮助,并且在实践中它运行得很好。

\n
\n\n

这是一个可能的解决方案。另一种可能性是拥有一个为您管理包含的工具,例如MakeDeps

\n\n

还有统一构建,有时称为 SCU,单一编译单元构建。有一些工具可以帮助管理它,例如https://github.com/sakra/cotire

\n\n

使用针对增量编译速度进行优化的构建系统也可能是有利的。我说的是 Google 的 Bazel 和类似的。但是,它不能保护您免受大量其他文件中包含的头文件的更改。

\n\n

最后,有一个关于 C++ 模块的提案正在进行中,很棒的东西https://groups.google.com/a/isocpp.org/forum/#!forum/modules。另请参阅C++ 模块到底是什么?

\n