C语言程序运行需要的两大环境《C语言进阶》

目录

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

翻译环境分为两部分,编译+链接

第一步:预编译(预处理)

第二步,编译

第三步:汇编

关于运行环境分为四点:

关于链接库


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

ANSI C(标准C) 的任何一种实现中,存在两个不同的环境。
*第1种是翻译环境。 在这个环境中源代码被转换为可执行的机器指令。
在编译器中(以VS2019为例),我们写的C语言代码都是文本的信息(各种字符串,数据,结构体等),站在人类的角度,我们能够理解,但是计算机不行,代码需要翻译成计算机呢能够识别的指令:二进制指令

*第2种是执行环境。它用于实际执行代码。
代码经过翻译环境后生成的二进制指令代码,由执行环境来执行生成。

代码编译时生成可执行程序时的步骤:

1. 组成一个程序的每个源文件通过编译过程分别转换成目标代码( object code )。
2. 每个目标文件由链接器( linker )捆绑在一起,形成一个单一而完整的可执行程序。
3. 链接器同时也会引入标准 C 函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。
简述来说:
每一个源文件(.c),都单独经过编译器进行编译,生成目标文件(.obj),目标文件和链接库再通过链接器的处理(这个过程就叫链接),就生成了可执行程序(.exe)。
如下图

翻译环境分为两部分,编译+链接

  

编译本身也分为几个阶段:预处理 , 编译 ,汇编。

 接下来我们用一个简单的代码,源文件名(test.c),使用gcc这个编辑器,给大家演示整个过程;

第一步:预编译(预处理)

预编译的指令是:gcc 源文件.c -E - 源文件名 + .i 

1. 预处理 选项 gcc - E test.c - o test.i
预处理完成之后就停下来,预处理之后产生的结果都放在 test.i文件中,具体内容可看下图。

如下面的代码:

源文件文件名 :test.c

#include<stdio.h>

//定义全局变量,赋值2023
int year = 2023;
#define M 100
int main()
{
	int a = M;
	printf("%d\n", M);

	return 0;
}

1.输入指令gcc test.c -E -test i

终端输出:


2.观察test.c和test .i的内容


 3.在test.i文件中查看

我们发现,在test.i整个代码的末尾,才是我们源代码的内容,那前面的几百行代码又是什么呢,是头文件<stdio.h>的整个内容包含进来了。同时细心的同学发现,test.i中没有了注释,也没有了宏定义的符号M了,所以预处理的作用是:

  1. 注释的删除
  2. #include<stddio.h>头文件的包含
  3. #define 符号的替换
  4. 文本操作
  5. 所以的预处理指令都是在预处理阶段处理的
第二步,编译

编译指令:gcc -S 源文件.c / gcc -S 源文件名 + .i

编译 选项 gcc - S test.c
编译 选项 gcc -S test.i   (编译时,这两个文件都可以输入指令中,都会生成文件test.s)
编译完成之后就停下来,结果保存在 test.s 中。
我们输入  gcc - S test.c 为例

1.输入指令gcc -S test.c / gcc -S test.i

终端输出:


2.生成了test.s文件的内容并展示test.s文件的内容

 


3.总结:

上面黄圈部分就是test.s的内容,里面就是汇编指令。编译的作用是:把c语言代码翻译成汇编指令 。编译的方式是通过:语法分析,词法分析,语义分析,符号汇总等方式。总的来说,编译就是把我们的c语言代码拆解分析,然后翻译成汇编指令给下一步汇编的动作。

第三步:汇编

汇编指令:gcc -c 源文件.c / gcc -c 源文件名 + .s

汇编 gcc - c test.c
汇编完成之后就停下来,结果保存在 test.o 中。

 1.输入指令gcc -c test.c / gcc-c test.s

终端输出:


 

2.生成了test.o的目标文件

但是你会发现这是test.o目标文件存放的二进制文件,编译器是不支持显示的的,如果仍要打开,如下图;


 


 3. 总结:

1.目标文件中存放的是二进制的指令

2.汇编是把汇编指令翻译成二进制指令

顺便提一下:Linux下gcc编译产生的目标文件test.o,可执行程序test都是按照ELF的这种文件格式存储的 

最后,以上过程完成了编译,之后到链接过程

链接指令:gcc 源文件名.o -o 新文件名 

对目标文件进行链接。可生成一个可执行文件

 1.输入指令:gcc test.o -o vskkk

输出终端:


2,对vskkk的内容进行查看

 但是文件还是二进制的指令无法查看。


3.总结:

链接的作用是:

1.合并线段

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

 


关于运行环境分为四点:

运行环境相较于翻译环境就好理解的多了,通俗理解有以下几点:

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

关于链接库

我们知道再写C语言代码时,只要加上头文件 #include<stdio.h> ,就可以直接使用库函数了,比如scanf(),printf(),那为什么可以直接使用呢?原因是我们把这些库函数都已经提前编译好,打包好放在静态库中,可以直接提供给我们,比如我们熟悉的scanf函数,如下图的打红圈内容,标记部分后缀以LIB结尾的,就是静态库(.LIB),库函数的静态库和目标文件在链接器中发生链接生成可执行程序。程序就可以运行啦。


以上就是全部内容了,希望能帮助到大家,如果可以,也希望大家给博主点点赞支持一下,谢谢。如果有错误的地方,希望大家能在评论区批评指出,我会进行订正的。

 

  • 41
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 59
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 59
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值