翻译单元的常用定义是预处理之后(头文件包含,宏等与源文件一起)。这个定义相当清楚,C标准5.1.1.1,C11说:
C程序不需要同时翻译。该程序的文本保存在本国际标准中称为源文件(或预处理文件)的单元中。源文件以及通过预处理指令
#include
包含的所有头文件和源文件称为预处理转换单元。在预处理之后,预处理翻译单元被称为翻译单元。
更仔细地阅读第一句话:
C程序不需要同时翻译。
这意味着(对我来说),C程序可以在同一时间进行翻译,而不必将它们分成多个预处理源文件。 同样在同一段的末尾,标准说:
翻译单元可以单独翻译,然后链接以生成可执行程序。
可以(通常是)解释为编译单个目标文件,然后最终链接它们以生成单个可执行程序。但是,如果可以从上述语句中提出问题并询问:这是否意味着实现可以自由地将多个源文件视为单个翻译单元,尤其是对于以下调用:
gcc file1.c file2.c -o out
编译器可以访问整个源吗?
特别是,如果某个实现将file1.c
+ file2.c
(上述)视为单个翻译单元,是否可以将其视为不合规?
答案 0 :(得分:13)
在引用的第二行:
该程序的文本保存在本国际标准中称为源文件(或预处理文件)的单元中
如果有两个源文件,那么有两个预处理文件,因此有两个预处理翻译单元,因此有两个翻译单元。一个对应于每个源文件。
标准未定义源文件。我想编译器可以通过声明file1.c
和file2.c
毕竟不是源文件来说“我正在构建我自己的'源文件'版本!”并将它们连接起来,但这与程序员的期望不一致。我想你会很难说file1.c
不是源文件。
答案 1 :(得分:9)
但是,如果可以从上述声明中提出问题并询问:是否意味着实现可以将多个源文件视为单个翻译单元
没有。定义很明确:
源源文件以及通过预处理指令#include包含的所有头文件和源文件称为预处理转换单元。预处理后,预处理翻译单元称为翻译单元。
翻译单元是预处理一个源文件及其包含的结果。您可能同时翻译两个翻译单元并不意味着您可以将它们视为一个翻译单元。
答案 2 :(得分:6)
编译器可以同时自由翻译多个源文件,但是它们不能改变它们的语义。
将几个文件一起翻译可能会稍快一些(因为编译器只启动一次)并且将允许更好的整个程序优化:其他翻译单元中的被调用函数的源代码然后可以在其他翻译单元的调用点处获得。编译器可以检查被调用的代码并使用这些信息,就像使用单个翻译单元一样。 From the gcc 6.3.0 manual:
编译器根据程序的知识执行优化。编译 多个文件一次到单个输出文件模式允许编译器使用信息 在编译每个文件时,从所有文件中获得 。
可以检查被调用函数是否存在别名,指向对象的事实约束等,使编译器能够执行在一般情况下出错的优化。
当然,这些功能可以内联。
但是(预处理)翻译单元的语义(对应于预编译后的源文件,根据您的标准引用),编译器必须遵守这些语义。 @Malcolm提到了一个文件静态变量。我的直觉是,关于声明和声明顺序可能还有其他更微妙的问题。
另一个明显的源代码范围问题定义。从n1570草案,6.10.3.5:
宏定义持续(独立于块结构)直到相应的#undef 遇到指令或(如果没有遇到)直到预处理结束 翻译单位。
这两个问题都禁止简单的C源文件串联;编译器必须另外应用一些基本逻辑。
答案 3 :(得分:5)
翻译单元表示点C文件。所有意图和目的,包括其相关的点h包括。很少#include指令用于添加其他文件类型或其他点C文件。
静态变量仅在翻译单元中可见。有一些公共函数与外部链接以及许多静态函数和数据项支持是很常见的。所以C转换单元有点像单例C ++类。如果编译器没有正确处理静态,则它是不符合的。
通常为每个翻译单元创建一个目标文件,然后由链接器链接它们。这实际上并不是标准规定的,而是在文件创建和编译成本相对较慢的环境中做事的自然而明显的方法。