C语言程序的翻译环境和执行环境

简介: C语言程序的翻译环境和执行环境

一、概述:翻译环境、执行环境

在ANSI C(标准C语言)的任何一种实现中,都存在两种环境:

1.翻译环境

在这个环境中,源代码被转换为可执行的二进制指令

在一个项目工程中,test.c就是源文件(源代码),可以在存放该项目工程的文件夹中找到该源文件。该源文件存放的是文本信息代码,可以直接用记事本打开,可以看到源代码

这样的源代码并不能直接运行,而是要通过翻译环境形成一个可执行程序text.exe,该可执行程序中存放的是二进制指令(机器指令)。同样也可以用记事本打开,但是打开后看到的是一堆乱码,因为存放的都是二进制的信息,记事本打开无法查看。

2.执行环境(运行环境)

用于实际执行代码(执行二进制指令)

当源文件test.c通过翻译环境产生可执行文件test.exe后,该可执行文件就可以通过执行环境执行,最终得到执行结果。

二、详述翻译环境——编译环境、链接环境

在翻译环境下,又分为两个环境:编译环境和链接环境

1.编译环境

源文件test.c通过编译器生成目标文件test.obj(Linux环境下的目标文件时test.o),该目标文件中存放的是二进制指令,用记事本打开同样是一堆乱码。

(VS2022环境下的编译器是cl.exe)

如果有多个源文件,那么这些源文件都要单独通过编译器生成对应的目标文件

2.链接环境

所有目标文件和链接库经过链接器的处理最终生成一个可执行文件test.exe

(VS2022环境下的链接器是link.exe)

链接库:是Windows系统中封装代码和数据以及实现资源共享的一种方式,本质上是已经编译好的二进制指令文件(机器指令文件)

例如包含头文件时使用的C语言标准库就是以链接库的形式和其他目标文件通过链接器链接

三、详述编译过程——预编译、编译、汇编

编译器对源文件进行编译的具体过程分为3步:预编译(预处理)、编译、汇编

1.预编译(预处理)

预编译时,编译器会进行以下动作:

1.将所有的注释替换为空格

2.将#define定义的标识符(宏)替换为对应的常量或函数(宏展开)

3.将包含的头文件中所有的内容以及源文件代码整合并生成一个test.i文件

(预处理后得到的test.i文件仍然是C语言代码)

VS2022环境下,将编译器设置改为预处理到文件,这样编译器会将预处理完成后的结果放到test.i文件。相比于源文件,该test.i文件末尾代码是进行了注释替换和宏展开的源代码,上面还有一万多行代码是将头文件所包含的所有内容。

2.编译(Linux环境下测试)

将test.i文件的C语言代码翻译成汇编代码,存放到test.s文件中

编译器如何将C语言代码翻译成汇编代码?
(1)词法分析

源代码程序被输入扫描器,扫描器的任务就是进行简单的词法分析。将代码中的字符分割成一系列的记号(关键字、标识符、字面量、特殊字符等)。

例如下面代码,代码中的字符可被分割成一系列的记号:

(2)语法分析

语法分析器对扫描器扫描产生的记号进行语法分析,从而产生语法树。这些语法树是以表达式为节点的树。

(3)语义分析

主要是检查是否结构正确的句子所表示的意思也合法、执行规定的语义动作(如:表达式求值、符号表填写、中间代码生成等)

(4)符号汇总

将所有源文件的全局符号汇总起来,包括全局变量名、全局函数名、main。(因为只有全局的函数、变量才涉及到跨文件使用)

3.汇编(Linux环境下测试)

将test.s汇编代码通过汇编器翻译为二进制指令,存放到test.o目标文件中(Windows环境下的目标文件为test.obj)

汇编器如何将汇编代码翻译成二进制指令?
(1)生成符号表

每个源文件都有自己的符号,汇编器会将源文件各自的符号列成一个表,并为每个符号给予地址。

例如,在下列项目中,有两个源文件 add.c 和 test.c ,汇编器在各自目标文件(.obj)中文件中生成符号表

add.obj

test.obj

四、详述链接过程——合并段表、符号表的合并与重定位

1.合并段表

在gcc编译器(Linux环境)中,所有生成的目标文件和二进制文件都是按照 elf 文件格式组织的。将所有的目标文件或二进制文件分成不同的段,每个段存放不同的数据。

合并段表就是将这些目标文件和二进制文件相同的段进行合并,生成二进制可执行文件

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

每个目标文件都有自己的符号表,需要将这些符号表进行合并

最终去查找函数的时候,只需要通过这个合并的符号表根据各符号的地址去查找即可

正是因为符号表合并的存在,才可以进行函数等的跨文件调用。

如果程序运行时出现了未定义的外部符号报错,说明源文件中并未定义该符号。根据地址查找该符号时,找不到该符号的定义。

五、详述运行环境——程序的执行过程

程序的执行过程
1.程序载入内存中

在有操作系统的环境中,该操作由操作系统完成。在独立的环境中,该操作由手工完成,或者通过可执行代码置入只读内存来完成。

2.调用main函数

程序载入内存完成后,紧接着便调用main函数

 

3.执行程序代码

此时程序调用一个运行时堆栈,存储函数的局部变量和返回地址。同时也调用一个静态内存,存储静态变量和全局变量,存储于静态内存中的变量在程序的整个执行过程中一直保留它们的值。

 

4.终止程序

正常终止main函数,或发生意外终止main函数

目录
相关文章
|
3月前
|
存储 自然语言处理 编译器
【C语言】编译与链接:深入理解程序构建过程
【C语言】编译与链接:深入理解程序构建过程
|
5月前
|
编译器 C语言 计算机视觉
C语言实现的图像处理程序
C语言实现的图像处理程序
228 0
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
73 5
|
2月前
|
C语言
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性。本文探讨了C语言中的错误类型(如语法错误、运行时错误)、基本处理方法(如返回值、全局变量、自定义异常处理)、常见策略(如检查返回值、设置标志位、记录错误信息)及错误处理函数(如perror、strerror)。强调了不忽略错误、保持处理一致性及避免过度处理的重要性,并通过文件操作和网络编程实例展示了错误处理的应用。
78 4
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
65 1
|
2月前
|
网络协议 物联网 数据处理
C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势
本文探讨了C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势。文章详细讲解了使用C语言实现网络通信程序的基本步骤,包括TCP和UDP通信程序的实现,并讨论了关键技术、优化方法及未来发展趋势,旨在帮助读者掌握C语言在网络通信中的应用技巧。
50 2
|
2月前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
44 1
|
3月前
|
存储 文件存储 C语言
深入C语言:文件操作实现局外影响程序
深入C语言:文件操作实现局外影响程序
|
4月前
|
存储 编译器 程序员
C语言程序的基本结构
C语言程序的基本结构包括:1)预处理指令,如 `#include` 和 `#define`;2)主函数 `main()`,程序从这里开始执行;3)函数声明与定义,执行特定任务的代码块;4)变量声明与初始化,用于存储数据;5)语句和表达式,构成程序基本执行单位;6)注释,解释代码功能。示例代码展示了这些组成部分的应用。
153 10
|
3月前
|
Linux C语言 iOS开发
MacOS环境-手写操作系统-06-在mac下通过交叉编译:C语言结合汇编
MacOS环境-手写操作系统-06-在mac下通过交叉编译:C语言结合汇编
54 0