C语言进阶(9)

程序的执行时有两种环境,一种是翻译环境,另一种是执行环境。程序先经过编译成为obj的后缀的文件,然后将文件和链接库链接起来,然后将形成可执行程序,前者时翻译环境,后者时执行环境。(链接库就是库函数的所在和一些其他的)

1.翻译环境

翻译分为编译和链接,编译又分为预编译,编译和汇编;链接又分为合并段表和合并符号表和重定位。

预编译就是将一些引用的头文件转换和,#definde定义的进行替换,注释的删除等,就可以得到预编译的程序文件(后缀时.i)

编译就是将预编译的文件由C语言代码转变为汇编代码,编译器要进行语法分析,词法分析,符号汇总,语义分析的操作,得到后缀为.s的编译文件。其中语法分析就是将整个程序中函数,全局变量等进行汇总。

汇编就是将汇编代码转变成二进制指令和形成符号表,把汇编文件转变成以obj结尾的目标文件。这个符号表就是将每一个obj目标文件就是将符号汇总中进行匹配地址,就可以得到符号表。(如果没有函数体只是函数声明,就匹配一个无效地址)

链接的合并段表就是将不同文件(obj文件是linux elf文件的格式,内容是一段一段的)每一段进行合并。

链接的符号表的合并和重定位,就是将不同文件中的符号表进行合并,相同的符号,删除无效地址的符号,得到全新的符号表。重新根据符号的地址定位,最终得到可执行程序。

2.执行环境

执行环境的具体过程是

(1)将文件载入内存中;

(2)调用main函数

(3)执行程序代码和函数堆栈,存储函数的局部变量和返回地址;

(4)终止程序(有可能是意外终止和正常终止)

下面介绍预处理的详解

3.预处理符号

在编译器中自带一些符号,他们可以显示编译的一系列信息,相当于存储这些信息的变量:

FILE //进行编译的源文件

LINE //文件当前的行号,就是显示当前代码所在编译器的行号

DATE //文件被编译的日期

TIME //文件被编译的时间

STDC //如果编译器遵循ANSI C,其值为1,否则未定义

下面是使用示例

\是续行符,可以将代码延申到下一行。

4 .#define

(1)#define定义标识符

define可以定义常量,代码等,本质上是替换,将定义的替换成原来的,在进行汇编。

如下

(2)#define定义宏

宏就是一种类似函数形式,本质上是将宏参在文本中进行替换。然后将文本在主函数中进行替换后运算。

宏的声明方式是#define name( parament-list ) stuff,其中parament-list是宏参,是传给宏的参数,stuff是文本,然后就会进行文本宏参的替换和代码的替换。

下面是使用示例:

经过替换后可以写成

cs 复制代码
int main()
{
	printf("%d", ((2)+(3)));
	return 0;

}

经过完整的替换,文本是什么样就替换成什么样,这一点很重要!!!

我们为了防止出现出乎意料的结果,我们要每一个宏参加括号,整个文本加括号。

宏参可以出现其他#define定义的变量,但是不可以出现递归,字符串常量时不被检索。

宏和函数的对比:

函数

函数代码只出现于一个地方,每次使用这个函数时,都调用那个地方的同一份代码 存在函数的调用和返回的额外开销,所以相对慢一些

函数参数只在函数调用的时候求值一次,它的结果值传递给函 数。表达式的求值结果更容易预 测。

函数参数只在传参的时候求值一 次,结果更容易控制。

函数的参数是与类型有关的,如 果参数的类型不同,就需要不同的函数,即使他们执行的任务是 不同的。

函数是可以逐语句调试的

函数是可以递归的

#define定义宏

每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长

宏参数的求值是在所有周围表达式的上下文环境里, 除非加上括号,否则邻近操作符的优先级可能会产生 不可预料的后果,所以建议宏在书写的时候多些括号。

参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果。

参 数 类 型 宏的参数与类型无关,只要对参数的操作是合法的, 它就可以使用于任何参数类型。

宏是不方便调试的

宏是不能递归的

(3)#和##

#是将非字符转变成字符

##是将两个符号合并成一个符号,这样的连接产生已申明的标识符,否则无效。

下面是使用示例

#和##只能在宏中使用。

(4)#undef

#undef就是将定义的宏进行删除,当我们需要重命名宏,发现重复时,就可以使用#undef来删除宏。

相关推荐
明月看潮生16 分钟前
青少年编程与数学 02-003 Go语言网络编程 15课题、Go语言URL编程
开发语言·网络·青少年编程·golang·编程与数学
南宫理的日知录27 分钟前
99、Python并发编程:多线程的问题、临界资源以及同步机制
开发语言·python·学习·编程学习
逊嘘43 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
xinghuitunan44 分钟前
蓝桥杯顺子日期(填空题)
c语言·蓝桥杯
Half-up1 小时前
C语言心型代码解析
c语言·开发语言
Source.Liu1 小时前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng1 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马1 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng1 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
Jacob程序员1 小时前
java导出word文件(手绘)
java·开发语言·word