【问题标题】:Why to split C files into multiple ones为什么要将C文件拆分成多个
【发布时间】:2017-05-25 18:17:09
【问题描述】:

首先,我知道如何将一个 C 文件拆分为多个。

我的问题是,除了可读性之外,还有其他优势吗?拆分C文件的主要原因是什么?

【问题讨论】:

  • 这个C++ answer 列出了一些原因...但是您可以从上一个问题中自行搜索,比在这里发布问题要快。
  • 能够在多个产品中重复使用特定部分而不必一直重写它是很好的。想象一下,必须重写代码来管理每个需要 USB 闪存驱动器的项目。另外,想象一下尝试滚动 500,000 行 main.c...
  • 如果您有一个相当大的项目,它会增加代码的模块化、可维护性和易读性。您可能会在编译时间上有一些改进,因为您只需重新编译相互依赖的文件。它还允许您在任何地方重用您的代码,而无需在内存中多次加载(减少内存使用),这样做可以降低复制粘贴代码出错的可能性。
  • 还有助于分离formfunction
  • 启用数据隐藏,启用功能本地化,增强可读性,增强可测试性,启用功能范围、数据定义、数据的限制,允许更好地定义接口(通过头文件)等

标签: c file split header


【解决方案1】:

如果你将一个大的 C 文件分割成几个翻译单元,你实际上必须在一些常见的包含头文件中声明所涉及的函数(例如extern)。

拆分的优点是增量构建时间可能会变得更短。如果您只更改一个函数中的一个语句,您只需要编译定义该函数的文件(如果该文件很小,它的编译速度很快)。但是,编译器需要解析所有的头文件。您可能想在头文件中定义static inline 函数(这会使它们变得更大)。

拆分的缺点是开发人员可能更难找到给定的函数(但像ctags 这样的工具有帮助)并且编译器可能优化得更少(例如,不会内联一些函数调用,除非你启用链接时间优化)

所以这是一个品味和习惯的问题。就我个人而言,我喜欢拥有超过一千行(可能少于一万行)的 C 或 C++ 文件,但是 YMMV。而且我不喜欢每个文件只有一个功能(少于一百行)的项目(在这种情况下你需要很多功能)。但是拥有一个十万行的大源文件通常是不合理的。

我还发现将相关函数放在一起的源文件更具可读性(因为在一个文件中搜索函数定义比在多个文件中搜索更简单)。

请注意,头文件可能会扩展为相当大的内容(在现代 C++ 中更是如此:像 <vector><map> 这样的标准头文件可能会扩展为超过一万行代码),例如<stdio.h> 扩展到两千行(在我的 Debian/Linux/x86-64 上),因此拥有大量小源文件会减慢整个构建时间(因为编译器确实会看到 preprocessed 形式,之后#include 指令的扩展)。

使用GCC,您可能想要一个标头(包括其他标头)和pre-compile

顺便说一句,将一个大文件分成几个小文件,或者合并几个小文件并不是什么大问题。所以我认为这不是很重要。

在某些情况下(在小型微控制器上嵌入 C 程序,Arduino 之类),二进制程序大小非常重要,这可能是拥有许多目标文件(如此多 C 源文件)的原因,因为您将只链接那些真正需要的。

【讨论】:

  • "这可能是拥有许多目标文件(如此多的 C 源文件)的原因,因为您只会链接那些真正需要的文件。" 如果是这样的话这种情况下,那个工具链可能不是很好。体面的嵌入式链接器应该只能从目标文件中选择使用过的函数。
【解决方案2】:

如果您要将函数放置在可能被许多不同程序使用的库中,那么将每个函数放置在单独的文件中具有明显的优势。

假设库包含 500 个函数,program1 仅引用其中的 2 个,而 program2 引用其中的 150 个。然后只有 2 个函数会被加载到第一个可执行文件中,而只有 150 个函数会被加载到第二个可执行文件中。

如果所有函数都包含在一个文件中,则所有 500 个函数都将加载到每个程序中,从而使它们变得非常大并且包含从未使用过的代码。

【讨论】:

  • 静态库实际上是这样,而不是共享库(例如 Linux 上的lib*.so),这很常见。
  • 是的,但是使用共享库意味着要执行程序的每个平台除了可执行文件之外还必须安装库。使用静态库 (*.a) 时,所有内容都加载到可执行文件中,并且库不需要出现在任何地方,除非在创建程序的平台上。
猜你喜欢
  • 2021-06-12
  • 2021-10-29
  • 2021-11-06
  • 1970-01-01
  • 2013-11-29
  • 2011-04-04
  • 2013-08-24
  • 1970-01-01
  • 2016-11-06
相关资源
最近更新 更多