C:关于翻译单位的澄清



如果我们有两个.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,这让我认为"两个源文件因此是两个翻译单元。">

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

将可执行文件的生成视为两步过程:首先,将每个翻译单元编译为一个对象文件;让我们称之为编译器。第二,将对象文件链接到一个可执行程序;让我们称之为链接器。

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

在您的示例中,main.csub.c可能是翻译单元,而sub.h本身不是翻译单元(它只是"包含"在其他翻译单元中,并在编译过程中考虑)。

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

注意,即使是.h文件也可能包含一个完整的程序;但是,除非您将环境配置为该.h文件是自己编译的,否则它不会生成对象文件。

以下是C标准对此的说明:

一个源文件以及通过预处理指令#include包含的所有头文件和源文件被称为预处理翻译单元。在预处理之后,预处理翻译单元被称为翻译单元。[..]以前翻译的译文单元可以单独保存,也可以保存在库中。程序的独立翻译单元通过(例如)调用标识符具有外部链接的函数、操作标识符具有外部连接的对象或操作数据文件来进行通信。翻译单元可以被单独翻译,然后随后被链接以产生可执行程序。

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

所以在这两种情况下,你都有两个翻译单元。其中一个来自编译器预处理main.c#include指令中包含的所有内容—即CCD_ 19和可能的CCD_。第二个来自编译器对sub.c做同样的事情。

第一个例子和第二个例子的不同之处在于,在第二个示例中,您将"不同的翻译单位"显式存储为对象文件。

请注意,没有将一个对象文件与任意数量的转换单元关联的规则。GNU链接器是能够将两个.o文件连接在一起的链接器的一个示例。

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

这里的区别:

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

是因为标头不必是源文件。类似地,#include指令中<...>的内容不需要是有效的文件名。编译器如何准确地使用命名头<...>"..."是实现定义的。

相关内容

  • 没有找到相关文章

最新更新