例如,过去的SysInternals工具“ FileMon”具有内核模式驱动程序,其源代码完全位于一个4,000行文件中。有史以来第一个ping程序也是如此(〜2,000 LOC)。
例如,过去的SysInternals工具“ FileMon”具有内核模式驱动程序,其源代码完全位于一个4,000行文件中。有史以来第一个ping程序也是如此(〜2,000 LOC)。
Answers:
使用多个文件总是需要额外的管理开销。必须设置具有单独的编译和链接阶段的构建脚本和/或makefile,确保正确管理不同文件之间的依赖关系,编写“ zip”脚本以便通过电子邮件或下载更容易地分发源代码,等等。上。今天的现代IDE通常会承担很多负担,但是我可以肯定,在编写第一个ping程序时,尚无此类IDE。而对于文件小为〜4000 LOC,没有它,管理多个文件,你也这样的IDE,权衡之间的开销提及并使用多个文件的好处可能让人们做出的单个文件的方式作出决定。
因为C不擅长模块化。它变得凌乱(头文件和#includes,外部函数,链接时错误等),并且引入的模块越多,它就越棘手。
更多现代语言具有更好的模块化功能,部分原因是他们从C的错误中学到了东西,并且可以更轻松地将您的代码库分解为更小,更简单的单元。但是对于C语言,避免或最小化所有麻烦可能是有益的,即使这意味着将原本会被认为过多的代码集中到一个文件中也是如此。
除了历史原因外,在现代的性能敏感软件中也有使用它的原因。当所有代码都在一个编译单元中时,编译器可以执行整个程序的优化。使用单独的编译单元,编译器无法以某些方式(例如,内联某些代码)优化整个程序。
当然,链接程序除了可以执行编译器的功能外,还可以执行一些优化,但不是全部。例如:现代链接器非常擅长隐藏未引用的函数,即使跨多个目标文件也是如此。他们也许可以执行其他一些优化,但是没有什么比编译器可以在函数内完成的优化更重要。
SQLite是一个著名的单一源代码模块示例。您可以在“ SQLite合并”页面上阅读有关它的更多信息。
1。执行摘要
超过100个单独的源文件被合并为一个名为“ sqlite3.c”且称为“合并”的C代码大型文件。合并包含应用程序嵌入SQLite所需的所有内容。合并文件的长度超过180,000行,大小超过6兆字节。
将SQLite的所有代码组合到一个大文件中,可以使SQLite的部署更加容易-只有一个文件可以跟踪。由于所有代码都在一个翻译单元中,因此编译器可以更好地进行过程间优化,从而使机器代码的速度提高5%到10%。
$(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(CFILES)
要比将所有内容移动到单个soudce文件要容易得多。您甚至可以将整个程序编译为传统构建脚本的替代目标,该传统构建脚本将跳过重新编译未更改的源文件,类似于人们可能会关闭生产目标的性能分析和调试。如果所有内容都放在一个大堆中,则没有这种选择。这不是人们习惯的,但是没有什么麻烦。
因为C89没有inline
功能。这意味着将文件分解为函数会导致将值压入堆栈并四处移动的开销。这在1个大switch语句(事件循环)中实现代码时增加了相当多的开销。但是,与更模块化的解决方案相比,事件循环始终要高效(甚至正确)实现起来要困难得多。因此,对于大型项目,人们仍然会选择模块化。但是,当他们预先考虑了设计并可以在1条switch语句中控制状态时,他们选择了这一点。
如今,即使在C语言中,也不必牺牲性能来模块化,因为即使C语言中的函数也可以内联。
inline
C89编译器中没有关键字无法内联,这就是为什么您必须在一个巨型函数中编写所有内容的原因。您几乎应该永远不要将其inline
用作性能优化-不管怎样编译器通常都会比您更了解(并且也可以忽略该关键字)。
inline
关键字连接器有关的语义这比与否进行在线优化的问题更重要,但一些实现具有其他指令在内衬控制和这样的事情有时是非常重要的。在某些情况下,一个函数看起来太大了,不值得内联,但是不断折叠可以将大小和执行时间减少到几乎没有。没有大力推动内联的编译器可能不会...