关于C编译过程和库的链接

时间:2014-08-05 20:00:33

标签: c compilation linker include object-code

C库是否与目标代码 首先与源代码相关联,以便稍后使用目标代码?我的意思是,看看Cardiff School of Computer Science & Informatics's website处的图片 :

Compile process

它" 奇怪"在生成对象代码之后,库被链接。我的意思是,我们在使用包含时使用源代码!

那么.. 这实际上是如何运作的?谢谢!

3 个答案:

答案 0 :(得分:4)

该图表是正确的。

当您#include标题时,它实际上会将该标题复制到您的文件中。标题是类型和函数声明和常量等的列表,但不包含任何实际代码(尽管有C ++和内联函数)。

我们举个例子: library.h

int foo(int num);

<强> LIBRARY.C

int foo(int num)
{
    return num * 2;
}

<强> yourcode.c

#include <stdio.h>
#include "library.h"
int main(void)
{
    printf("%d\n", foo(100));
    return 0;
}

当您#include library.h 时,您会收到foo()的声明。 此时,编译器对foo()或它的作用一无所知。尽管如此,编译器仍可以自由地插入foo()的调用。链接器在 youcode.c 中看到foo()的调用,并看到 library.c 中的代码,知道对foo()的任何调用应该去那个代码。

换句话说,编译器告诉链接器要调用哪个函数,并且链接器(给定所有目标代码)知道该函数实际位于何处。

(感谢Fiddling Bits进行更正。)

答案 1 :(得分:3)

库中的包含通常只包含库接口 - 因此在最简单的情况下,库提供的.h文件包含函数声明,编译的函数在库文件中。因此,您使用库头中提供的库函数声明来编译源代码,然后链接器将编译器库函数添加到您的可执行文件中。

答案 2 :(得分:3)

查看工具链中的每件作品可能会有所帮助,因此请使用图片中的方框。

<强>预处理器

这实际上是一个文本编辑器做了一堆替换(好吧,真的很简单)。预处理器的一些功能是:

  • 对#defines执行简单的基于文本的替换。因此,如果我们的文件中有#define PI 3.1415,然后我们会有angle = angle * PI / 180;这样的行,则pre =处理器会将此行转换为angle = angle * 3.1414 / 180;
  • 我们遇到#include的任何时候,我们可以想象预处理器去获取该文件的全部内容并将文件上的内容粘贴到#include所在的位置。 (然后我们回去进行替换。
  • 我们也可以使用#pragma指令将选项传递给编译器。

最后,我们可以通过对gcc使用-E选项来查看运行预处理器的结果。

<强>编译

预处理器的输出仍然是文本,并且它不包含编译器需要能够处理文件的所有内容。现在编译器做了很多事情(当我描述这个过程时,我通常会打破这个框)。编译器将处理文本,对其进行词法分析,将其传递给解析器,验证程序是否满足语言的语法,输出语言的中间表示,执行优化并生成汇编代码。

我们可以通过使用gcc的-s选项来查看运行汇编程序的结果。

<强>汇编

编译器的输出是一个汇编列表,然后传递给汇编程序(在Linux上最常见的`gas&#39;(GNU汇编程序)),它将汇编代码转换为机器代码。另外,汇编程序的任务是构建一个未定义引用的列表(即。您编写的函数的库函数,该函数在另一个源文件中实现。)

我们可以通过对gcc使用-c选项来查看获取汇编程序输出的结果。

<强>接头

链接器的输入将是汇编器的输出(通常称为目标文件并使用扩展&#39; o),以及各种库。从概念上讲,链接器负责将所有内容挂钩,包括修复对库中函数的调用。通常,在Linux中执行链接的程序是ld,我们只需运行gcc就可以看到链接的结果而没有任何特殊的命令行选项。

我简化了链接器的讨论,希望我能告诉你链接器的功能。


我对您引用的图像的唯一问题是,我将移动阶段&#34;对象代码&#34;紧接着汇编框的下方,同时我会移动标有&#34; Libraries&#34;的箭头。下。我觉得这表明汇编程序中的目标代码与库结合在一起,并由链接器组合起来构成可执行文件。