C语言程序环境(翻译+执行)

我们对C语言有了一定的了解之后会不会思考,我们写出来的源文件通过怎样的处理就在黑框框中显示出来, 变得可执行了呢?

程序的翻译环境和执行环境

在ANSIC(C语言的标准)的任意一种实现中,都存在以下两个环境:

  1. 翻译环境,将我们写出来的 test.c 源代码转换成 test.exe (可执行的二进制指令)
  2. 执行(运行)环境,用于将翻译中产生的 test.exe 进行执行。

翻译环境 

我们写的所有 test.c add.c等源文件都会单独的通过编译器的处理,从而生成相对应的 test.o、add.o等以.o为后缀的目标文件,最后通过链接器将程序所需要的链接库和生成的.o目标文件进行处理生成.exe或.out为后缀的可执行文件。


编译(生成目标文件)

预编译(预处理)

预编译又称为预处理,是做些代码文本的替换工作。 处理以# 开头的指令,比如拷贝 #include 包含的文件代码,#define 宏定义的符号替换 ,注释的删除,条件编译(如#if #ififdef #pragma pack)等,就是为编译做的预备工作的阶段。

gcc -o test.i -E test.c 指令将test.c的源文件通过gcc -E指令进行预处理的工作,并将生成的结果放到test.i的文件中。

#include<stdio.h>

#define num 7
int main()
{
    printf("%d:haha\n",num);//简单打印

    return 0;
}

test.i文件部分内容:

其实int main上面的所有内容其实就是将<stdiio.h>文件中的声明等内容包含过来了(实际上就是拷贝)

编译

通过对源代码的词法、语法、语义分析,符号汇总,把C语言的代码翻译成汇编代码。

  • 词法分析:将输入的源程序代码中的字符流按照语言的词法规则分割成一个个的单元,同时会进行检测是否有不符合词法规定的字符单元,如果有就会在该阶段报错。(如int num = 10;会被分割成int(关键词) ,num(标识符),=(运算符),10(常量),;(界限符))。
  • 语法分析:基于词法分析得到的单词按照语法规则构建出语法树,如下结构:
  • 语义分析:在语法结构正确的基础之上,进一步进行代码语义的分析,其实就是检测代码中的变量是否先声明后定义,以及数据类型是否匹配,数据运算是否合法等。
  • 符号汇总:在编译阶段会对每一个源文件各自进行符号汇总的过程,其实就是在源文件中汇总文件内部以及外部定义的(在本文件作用域可见)符号,如全局变量、函数名等(而局部变量会是在运行时创建分配空间的)。

gcc -o test.s -S test.i 指令可以将刚刚预处理生成的test.i文件进行编译生成test.s的文件: 

汇编

将编译所产生的汇编代码转换成目标文件(后缀为.o的二进制文件),并形成符号表

形成符号表:将符号汇总的所有符号都关联上相对应的地址(也就是确定它们在目标文件中的相对偏移量信息)形成符号表,其实就是为后续链接时关联合并所有的符号表做准备。但这个地址是否有效需要在链接阶段进行符号表的合并与重定位时才能检查出来

gcc -o test.o -c test.s(编译条件大小写不同,上面两次的-E -S大写,汇编-c小写) 指令可以将编译生成的test.s文件汇编生成test.o的二进制文件。

链接(生成可执行文件)

C语言链接的作用是将机器码(编译所产生的目标文件)与所用到的链接库链接到一起生成可执行程序(针对静态库,链接器会将程序中用到静态链接库中的代码和数据提取出来整合可执行文件里。而针对动态库,链接器会将程序引用动态链接库中的符号进行解析,然后再可执行文件中记录好相应的引用信息,等到运行时,OS依据记录的信息去已经加载到共享区的动态库里查找)。

  • 符号解析:将汇编阶段生成的目标文件,以及所用到库文件中的函数变量等符号信息进行解析,从而确定其定义和引用的位置。建立符号引用与定义之间的关联。
  • 符号表的合并: 在链接期间,会将所有目标文件生成的符号表进行判断,并将相同的符号名的不同地址进行合并成一个有效地址的符号名。
  • 符号表的重定位:由于生成的目标文件的符号表所记录的地址其实都是通过相对偏移量的方式进行编址的,而符号表的重定位其实就是依据最终生成的可执行文件的整体布局方式,将相对地址转换成虚拟地址空间中的虚拟地址,保证程序在运行时能够通过虚拟地址结合页表访问对应物理地址的的代码和数据信息。
  • 合并段表:编译产生的各种目标文件(二进制文件)是具有相同的elf格式(elf格式文件,其中包含了所用函数与函数在对应库文件中的相对其实位置的偏移量信息,以便在调用的时候可以通过偏移量找到对应位置),而合并段表就是将我们生成的各种elf格式的目标文件进行合并生成一个最终的elf格式的可执行文件。 

 执行环境

执行过程:

  1. 程序(二进制指令)载入内存。 一般这是由操作系统进行。 在独立的环境中程序的载入手动安排,也可以通过可执行代码置入只读内存来完成。
  2. 程序的执行是由main函数开始。
  3. 开始执行程序代码,使用一个运行时堆栈(函数栈帧)存储函数的局部变量和返回值地址,同时在数据段中存储程序中的静态变量和全局变量等处理,直到程序结束。
  4. 终止程序。 main函数正常结束或者意外结束。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CR0712

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值