C:关于翻译单位的澄清

时间:2017-01-29 23:38:44

标签: c translation-unit

如果我们有两个.c文件和一个.h文件:main.c sub.c sub.h,其中

的main.c

#include "sub.h"
...

sub.c

#include "sub.h"
...

我们可以使用i)

编译程序
gcc -o a.out main.c sub.c

或ii)

gcc -c main.c
gcc -c sub.c
gcc -o a.out main.o sub.o

鉴于这种情况,预处理器输出一个或两个翻译单元

我很困惑因为:main.c包含sub.h,这意味着预处理器会输出一个编译单元。另一方面,在创建可执行文件之前,创建了两个目标文件main.osub.o,使我认为&#34;两个源文件因此是两个翻译单元。&#34; < / p>

我误解哪一部分?或者我在哪里犯错?

2 个答案:

答案 0 :(得分:6)

考虑将可执行文件生成为两步过程:首先,将每个翻译单元编译为目标文件;让我们称之为编译器。其次,目标文件链接到可执行程序;让我们称之为链接器。

&#34;翻译单位&#34;是第一步的问题。翻译单元是编译开始的每个文件(即传递给编译器的文件)。在大多数IDE中,有一些规则声明扩展名为.c.cpp的每个文件都作为输入传递给编译器,而其他文件则不是。因此,扩展名为.h.hpp.txt的文件通常不会直接传递给编译器。

在您的示例中,main.csub.c可能是翻译单位,而sub.h本身不是翻译单位(仅限&#34;包含&#34;在其他翻译中)单位并在编制过程中考虑。)

所以你得到两个目标文件,每个翻译单元一个。然后链接器会考虑这两个目标文件。

请注意,即使.h文件也可能包含完整的程序;但除非您将您的环境配置为此.h - 文件自行编译,否则它将无法生成目标文件。

答案 1 :(得分:3)

以下是C标准对此的评价:

  

源文件以及通过预处理指令#include包含的所有标头和源文件称为预处理转换单元。在预处理之后,预处理翻译单元被称为翻译单元。 [..]以前翻译过的翻译   单位可以单独保存或在图书馆保存。程序的单独翻译单元通过(例如)调用其标识符具有外部链接的函数,标识符具有外部链接的对象的操纵或数据文件的操纵来进行通信。翻译单元可以单独翻译,然后链接以生成可执行程序。

(资料来源:C99标准草案,5.1.1.1§1)

因此,在您的两种情况下,您都有两个翻译单元。其中一个来自编译器预处理main.c以及通过#include指令包含的所有内容 - 即sub.h和可能<stdio.h>以及其他标头。第二个来自编译器使用sub.c做同样的事情。

与您的第一个示例的区别在于,在后者中,您明确地将“不同的已翻译翻译单元”存储为对象文件。

请注意,没有规则将一个目标文件与任意数量的翻译单元相关联。 GNU链接器是is capable of joining two .o files together

的链接器的一个示例

据我所知,该标准没有指定源文件的扩展名。尽管如此,在实际方面,您可以#include.c个文件免费转换为其他文件,或将整个程序放在.h文件中。使用gcc,您可以使用-x c选项强制将.h文件视为翻译单元的起点。

这里的区别是:

  

源文件以及通过预处理指令#include包含的所有标头和源文件[...]

是因为标题不必是源文件。同样,<...>指令中#include的内容不必是有效的文件名。编译器如何使用命名头<...>"..."是实现定义的。