第24课【C文件的运行和编译】预处理 编译 汇编 链接

基本知识框架

在这里插入图片描述

课堂笔记

在ANSI C标准的实现中,存在两种环境:

  1. 编译环境:用于将源代码转换为可执行代码的环境
  2. 运行环境:用于实际执行代码的环境

运行环境

C语言程序运行基本示意图
在这里插入图片描述

程序载入内存

在有操作系统的环境中:这个步骤一般由操作系统去执行

在无操作系统的环境中:这个步骤需要手动去执行,但也可以是通过将可执行代码置入只读内存的形式来完成

执行主函数

执行main函数

启用运行时堆栈,静态变量区初始化

对于函数参数,返回值,局部变量,在内存中使用栈来保存

对于内存操作函数(malloc,free,calloc,realloc等)申请的内存,使用堆来保存

对于全局变量、静态变量和常量字符串一般存储在静态内存中

其他变量都存放在对应数据段中

结束程序运行

终止main函数运行,既可能是正常终止,也可能是错误终止

编译环境

C语言程序的基本编译流程
在这里插入图片描述

预处理

预处理的目的主要是:

  1. 处理预定义符号
  2. 处理伪指令
  3. 处理特殊符号
  4. 去除注释
预定义符号

预定义符号指的是C语言内置的,代表着特殊意义的符号包括:

__FILE__	//	当前进行编译的源文件
__LINE__	//	当前行号
__DATE__	//	当前日期
__TIME__	//	当前时间
__STDC__	//	当前编译器是否遵循ANSI C标准,如遵循,则为1,否则为未定义
伪指令

主要指以’#'开头的指令,如#define,#include等

宏定义
宏定义标识符
#define MAX_NUM	1000

功能:在预处理时,会用后者直接去替换前者
注意:

  • 可以大大增加程序的可读性。例如:
  1. 直接使用立即数会使得程序可读性变差,将其宏定义为便于理解的单词
  2. 将过长的变量宏定义为简单的单词,便于理解

是否要在宏定义后加 ;
一般来说不建议加,容易出现重复’;',从而引发一些逻辑问题

宏定义功能
#define MAX(a,b) ((a)>(b)?(a):(b))  

功能:可以根据需求,将要实现的功能定义为宏
注意:

  • 使用宏定义时,有约定俗成的习惯,宏名全部大写

可以有效的将宏定义与其他功能区分开

  • 可以使用#undef取消宏定义
  • 使用宏定义时,由于参数是直接无条件替换的,所以经常使用括号进行运算顺序以及参数完全隔离,以免出现意料之外的情况

例如:
#define MUX(a,b) a+b
MUX(5+6,6+7); //展开后就是5+6*6+7

  • 宏定义可以嵌套使用,但不能出现递归

嵌套使用宏定义时,要遵循下列的展开规则:

  1. 宏定义展开时,要先检查参数是否包含宏定义
  2. 如果参数包含宏定义,先展开参数的宏定义,再将展开后的参数带入到原宏定义中
  3. 重复上述步骤,直至参数不可以再展开
  • 宏定义中最好不要有带副作用的参数,例如对宏定义参数进行++运算

例如:
#define MAX(a,b) ((a)>(b)?(a):(b))
MAX(x++,y++). //展开后就是((x++)>(y++)?(x++):(y++))

  • 宏定义如果太长,可以用反斜杠’\'续行

例如:
#define PRINT_CHECK_NUM(a,max) printf("This Num is %d,%s than %d" \
, a, ((a)>(max))?("Bigger"):("Smalle \
r"), max) \

  • 字符串作为宏定义的参数

例如:
#define PRINT(FORMAT,VALUE) printf("String value is "FORMAT"\n",VALUE)
PRINT("%d",12) //展开后就是printf("String value is " "%d" "\n",12)


注意:字符串是可以自动连接的,所以输出的结果是String value is 12

  • 宏定义功能通常能起到和函数类似的作用,我们可以对比一下宏定义功能和函数的两者的优缺点
属性宏定义函数
代码长度宏定义在使用时,会将宏定义出现处的代码替换。这样的替换增加了代码量函数在使用时,仅需定义一次,之后的调用都不增加代码量
运行速度仅仅是代码的简单替换,速度快存在函数调用开销,更慢些
运算优先级由于宏定义直接替换的特性,使用时要经常使用括号来保证运算优先级,结果更具不可预料性函数传参时,即完成参数的运算,结果更容易预料
带副作用的参数由于宏定义直接替换的特性,运算结果容易受参数影响函数传参时,即完成参数的运算,结果更容易预料
参数类型宏定义的参数与参数类型无关,不进行参数类型检查,使用灵活但也很危险函数调用时会对参数进行类型检查,使用受限但是更加安全
调试宏定义不可以调试函数可以调试
递归宏定义不能使用递归函数可以使用递归
条件编译

某段代码,当满足条件的时候才进行编译

例如调试类代码。在大多是情况下我们不需要编译,只有在进行调试时需要编译。使用条件编译可以应对这类情况

单分支条件编译
#if (判断条件)
	// 代码段1
#endif

功能:判断条件为真时,编译代码段1

多分支条件编译
#if (判断条件1)
	// 代码段1
#elif (判断条件2)
	// 代码段2
#else
	// 代码段3
#endif

功能:判断条件1,条件2真假后,根据判断结果选择编译代码段

判断是否被定义
//	如果定义了MAX
#if defined(MAX)
#ifdef MAX

//	如果没定义MAX
#if !defined(MAX)
#ifndef MAX

条件编译的用法与分支语句中的if语句的用法类似

头文件包含

头文件包含可以使头文件中的内容替换到头文件包含处,从而实现引用头文件中定义的函数,变量等等

#include “private.h”	//	用于包含个人定义的头文件
#include <stdio.h>		//	用于包含C语言标准库的头文件

头文件查找的策略

  • 对于"个人头文件名"这样的包含方式,会先在当前源文件根目录下寻找此头文件,找不到的话再到C语言标准库中查找
  • 对于<C语言标准库头文件>这样的包含方式,直接到C语言标准库中进行查找

头文件重复包含的问题
当一个头文件被包含很多次时,也会被编译器相应的编译很多次,造成很多不必要的冗余。为了解决头文件被多次包含的问题,我们采用条件编译


头文件内容的一般格式为
#ifndef __TEST_H__
#define __TEST_H__
// 头文件内容
#endif

特殊符号
  • 使用#将宏定义参数转换成纯字符串

例如:
#define PRINT(FORMAT,VALUE) printf("#VALUE is "FORMAT"\n",VALUE)
PRINT("%d",1+1) //展开后就是printf("1+1 is " "%d" "\n",1+1)


注意:输出的结果是1+1 is 2

  • 使用##进行字符串拼接

例如:
#define ADD(code, num) sum##code+=num
int sum5 = 5;
ADD(5,10); //展开后就是sum5+=10;


注意:这里的sum##code拼接后的到的标识符sum5一定要是已经定义好的,否则就是未定义的

去除注释

C语言中的注释包括

  1. //开头的注释
//	我是注释
  1. 被/* */包括的注释
/* 我是注释 */

编译

在这一步,编译器会将预处理完毕的代码转换成汇编代码

要进行的工作主要包括:

  • 词法分析
  • 语法分析
  • 语义分析
  • 性能优化

这些都是很复杂的过程,具体可以去看《编译原理》这本书

汇编

在这一步,编译器会将汇编代码转换为机器码

链接

链接就是建立目标文件之间联系,最终打包得到可执行文件的过程

链接的意义
因为对于编译器而言,对某个源文件进行编译,得到的是对应目标文件。如果当前目标文件有调用库或者其他其他目标文件的话,那么是要建立它们之间联系的,链接就是建立这种联系的过程,这个过程是通过链接器完成的


链接器是一个独立的程序,可以将库文件或者多个目标文件打包到一起生成可执行文件

链接还分为

  • 静态链接:链接器直接将要调用的函数或者过程打包到可执行文件中,成为可执行文件的一部分。静态链接不依赖于外部文件,使得程序可以独立运行
  • 动态链接:链接器仅将要调用文件的信息或定位打包到可执行文件中,当文件执行时,再去调用相应的库。动态链接依赖外部文件,在使用时要确保外部文件存在且正确

基本知识框架Xmind文件下载

链接: 资源下载

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值