C语言 程序的编译、链接、执行

  • 一、 程序的环境
  • 1.1 方式一
  • 1.2 方式二
  • 1.3 函数库
  • 1.4 文件后缀名约定
  • 二、翻译环境
  • 2.1 预编译(预处理)
  • 2.2 编译
  • 2.3 汇编
  • 2.4 链接
  • 三、 执行环境


一、 程序的环境

在ANSI C的任何一种实现中,存在两种不同环境第1种是翻译环境,在这个环境中源代码文件被转换为可执行的机器指令(二进制代码)。第2种是执行环境(运行环境),它用于实际执行代码。标准规定,这两种环境可以不在同一台计算机上,即可以在计算机A中编译程序,在计算机B中执行程序。

对于这两种环境按步骤细节有两种划分方式

1.1 方式一

方式一将翻译环境按步骤细分为编译、链接两步,运行环境不变。这就是我们常说的程序的编译、链接、执行三步骤

执行链 java 执行链接_c语言

1.2 方式二

方式二将翻译环境按步骤细分为编译、链接两步,编译又细分为预编译、编译、汇编,执行环境不变。即:预编译、编译、汇编、链接、执行五步骤

执行链 java 执行链接_c语言_02


说明:方式一与方式二没有本质区别,方式二相对于方式一步骤划分更加细节,下文中以方式二详细介绍每个步骤所做的事情

1.3 函数库

在链接阶段,会将目标文件和函数库一起链接,这里的函数库指的是在源文件中用到C语言提供的各种库函数,这些函数存放在函数库中,在链接时候需要与目标文件一起链接

1.4 文件后缀名约定

C语言标准没有对文件后缀名进行规定,但在大多环境下有一套约定的文件后缀名
.h为后缀名的文件为C语言头文件.c为后缀名的文件为C语言源代码文件.i为后缀名的文件,是预编译后的C语言文件.s为后缀名的文件,是编译过后的汇编代码文件.o为后缀名的文件,是汇编后的目标文件(机器指令文件也称为二进制指令文件)。windows系统中目标文件以.obj为后缀名.out为后缀名的文件,是多个目标文件与函数库链接之后的可执行程序。windows系统中以.exe为后缀名

二、翻译环境

windows系统下的大多数IDE对于预编译、编译、汇编、链接实现细节进行了隐藏,为了观察细节,环境使用Linux系统下GCC编译器

2.1 预编译(预处理)

预编译的详细过程可以查看这篇博客:
预编译:将源代码文件(.c)进行预编译处理生成预编译文件(.i)
功能:

  1. 执行预处理指令,如: #include 、#define
  2. 删除所有注释

gcc -E 源文件 -o 预处理文件名 -E :预编译阶段结束后停止,将预编译后的数据输出到标准输出
-o :将输出到标准输出上的内容输出到指定文件

测试1:#include,将所包含的头文件引入

执行链 java 执行链接_预编译_03


由于<stdio.h>头文件内容太多,所以自定义<add.h>头文件测试测试2:#define ,标识符常量替换

执行链 java 执行链接_c语言_04

测试3:会删除源文件的注释

执行链 java 执行链接_开发语言_05

2.2 编译

编译:将预编译后的文件编译为汇编代码
功能:

  1. 语法分析
  2. 词法分析
  3. 语义分析
  4. 符号汇总(汇总全局符号,如全局变量、函数名)

gcc -S 预处理文件(或源文件) -o 编译文件名 -S :编译阶段结束后停止,将编译后的数据输出到标准输出

-o :将输出到标准输出上的内容输出到指定文件

执行链 java 执行链接_开发语言_06

2.3 汇编

汇编:把汇编代码转换为机器指令(二进制指令)的目标文件
该机器指令文件为elf格式,可用readelf命令查看内容
功能:

  1. 形成符号表
    gcc -c 编译后文件(或源文件) -c :进行汇编
  2. 执行链 java 执行链接_预编译_07


  3. 执行链 java 执行链接_c语言_08


2.4 链接

可执行程序(机器指令)为elf格式,可用readelf命令查看内容
链接:将多个目标文件和函数库链接为可执行程序
功能:

  1. 合并段表
  2. 符号表的合并和重定位

gcc 多个目标文件(或源文件) -o 链接后可执行程序名

执行链 java 执行链接_c语言_09

三、 执行环境

  1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成
  2. 调用main函数运行
  3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
  4. 终止程序,可以是正常终止main函数;也有可能是运行错误终止