如果我们有两个.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.o
和sub.o
,使我认为&#34;两个源文件因此是两个翻译单元。&#34; < / p>
我误解哪一部分?或者我在哪里犯错?
答案 0 :(得分:6)
考虑将可执行文件生成为两步过程:首先,将每个翻译单元编译为目标文件;让我们称之为编译器。其次,目标文件链接到可执行程序;让我们称之为链接器。
&#34;翻译单位&#34;是第一步的问题。翻译单元是编译开始的每个文件(即传递给编译器的文件)。在大多数IDE中,有一些规则声明扩展名为.c
或.cpp
的每个文件都作为输入传递给编译器,而其他文件则不是。因此,扩展名为.h
,.hpp
,.txt
的文件通常不会直接传递给编译器。
在您的示例中,main.c
和sub.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
的内容不必是有效的文件名。编译器如何使用命名头<...>
和"..."
是实现定义的。