2011-12-08 67 views
2

假设你的程序由两个源文件(main.c和auxiliary.c)和两个头文件(declarations.h和auxiliary.h)组成。关于GCC编译器和链接器的问题

然后你运行编译如下:

$gcc main.c auxiliary.c -o myprogram 

问题1:请问编译器创建一个单一的目标文件为我的计划(即,只是库丢失),还是会创建两个对象文件,每个源文件一个(然后将所有内容链接在一起)?

问题2:有没有必要单独调用链接器?因为如果你使用上面的命令,编译器会为你处理这个问题,对吧?

问题3为什么一些库自动链接(例如,stdio)以及为什么一些库需要额外的工作(例如,math.h需要在编译时添加-lm)。 -lm代表什么?

问题4:假设你有一个源文件,并且你的程序不需要任何外部库。这是否意味着您将从编译器获得的对象代码已经可执行了? (即,编译它像$ gcc -c main.c)。

+0

这东西是特定于每个实现。像使用“C”和“编译器”这样的通用标签来标记它并不合适,就像引用“the”C编译器一样。 –

+0

同意。我重新命名为“有关GCC编译器的问题” –

回答

3
  1. gcc创建每个源文件的目标文件,然后链接它们生成可执行文件。

  2. 你举的例子证明了gcc能链的所有所需的步骤

  3. 那就会自动链接是标准C库的库。其他需要指定。当你不需要atan2()时,这允许构建一个更小的可执行文件。
    -lm向编译器指示应找到数学库,其编号为m。在Unix上,其文件名为libm.solibm.a,具体取决于链接是动态的(在运行时执行并导致较小的可执行文件)还是静态的(在链接时执行并导致独立的可执行文件)。

  4. 不管怎样,它必须链接到标准C库。而且,目标代码的文件格式与可执行文件不同。

+0

4.技术上来说,它们都是ELF文件,但具有一些不同的属性。 –

+0

谢谢。还有一个问题:维基百科和其他资源如何说math.h是标准库的一部分? - > http://en.wikipedia.org/wiki/C_standard_library –

+0

在维基百科文章中有关于它的章节。而且,并非每种C的风味都符合最新的标准。 – mouviciel

1

问题1:与“-save-临时工”执行你的GCC的语句,你会看到,编译器会创建两个目标文件。

问题2:对链接器的调用是隐式的。 'gcc'命令实际上不是一个编译器,而是根据需要通过调用预处理器,编译器,汇编器和链接器来驱动编译过程。 在小程序中,让'gcc'处理所有内容可能是一个好主意,但对于大型程序和许多源文件,这意味着即使没有更改也会重新编译所有源文件。

问题3:这是一个惯例。 (m库是数学库。)

问题4:不,事实并非如此。总是有一些额外的代码必须链接来处理流程启动/拆卸需求。在Linux上,这些是crt1.o,crti.o,crtbegin.o和crtn.o文件。

+0

感谢您的回答。我猜测,当我在gcc中使用-c选项时,编译器会输出汇编代码,汇编器会将其转换为对象文件并停在那里,对吧?在这种情况下,是否可以停止在汇编代码步骤? (即,使gcc输出程序集而不是目标文件?) –

+1

@DanielS是的,这是可能的。看到这个:http://stackoverflow.com/questions/137038/how-do-you-get-assembler-output-from-c-c-source-in-gcc –

4
  1. GCC将通常使每个源文件中的一个对象。但有一个-combine选项可以告诉你,否则你想要的。当你有几十个源文件时重新编译所有东西并不是一个好主意(当你有更多的东西时,你将它们分割成库)。

  2. 历史。曾经有一段时间 - 共享库之前 - 数学库相对较大,并将其放入每个可执行文件中,即使那些不需要的可执行文件也被认为是浪费的(使用数学库涉及printf等功能的替代版本)你有没有用,即使成本)

  3. 我等着看一个程序,它不使用甚至标准库的任何部分(逻辑调用主要为exit(main(argc, argv))所以至少exit被称为完成)然后是启动和结束代码。