目录
程序的翻译环境和执行环境
在ANSI C(国际标准C)的任何一种实现中,存在两种不同的环境。
第一种是翻译环境,在这个环境中,源代码被转换为可执行的机器指令。
第二种是执行环境,在这个环境中,它用于实际执行代码。
翻译环境:
每个源文件单独经过编译器处理
我们随便打个代码
源文件就是我们这里后缀为.c的文件
这里后缀为.obj的文件,就是我们的目标文件~
最后那个可执行程序就是后缀为.exe的文件
运行环境:
过程:
1. 程序载入内存
2. 程序入口
3. 开始执行程序
4. 终止程序(可以正常终止,也可能意外终止)
预处理详解
预定义符号
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("FILE:%s LINE=%d DATE=%s TIME=%S i=%d \n", __FILE__, __LINE__, __DATE__, __TIME__, i);
}
return 0;
}
结果就是这样:
#define
1. #define定义标识符
我们在编译器中写的代码:
(注意:在我们#define标识符时,后面是不加上 ; 的)
在预处理中的代码:
将MAX替换成了100,然后将#define 删去
2. #define定义宏
SQUARE -- 宏名
X -- 宏的参数
X*X -- 宏的内容
(注意:定义宏的时候, () 需要紧紧贴在宏名后)
注意:宏的定义是直接替换的
但如果我们在参数中这样写:
结果:
结果应该为6的平方,也就是36呀,为什么会变成11呢?
原因是:宏的定义是直接替换的,此时5+1为X
那么到了后面X*X,就变成了5+1*5+1,先乘除,后加减,结果就成了11了~
知道了原理之后,我们就可以这样解决:
加上括号就好~
这里可能会有人有疑问:为什么外面还要加一个括号呢?
一张图来告诉你~
这里我们用10乘以DOUBLE(3),我们想要得到的是60,可是却得到33。
原因相信大家都懂了,就是因为10 先跟第一个X相乘再相加了~
即10 * 3 + 3,而如果我们在之前就加上了括号,就是
10 * (3 + 3)
所以我们最好还是加上括号~
#define替换规则
简单来说呢,就是这样一个步骤:
第一步:将M转换成100
第二步:将100+2替换参数名(X)
(注意!预处理是替换,不是计算!)
#和##
可以完成将参数插入到字符串中的操作
#
转换回去~
##
合并成一个符号~
带有副作用的宏参数
我们想要的本来是5 6 5,结果却出现了副作用(因为++永久改变了a,b的值)
宏与函数的对比
宏的优点:
宏运行更快
而函数的话,需要调用,又要传回参数,需要更多时间
宏的参数类型限制更加宽泛,比如整型浮点型都可比较~
而函数的话,这里就只能用整型(int类型)~
宏的缺点:
宏无法调试
可能带来运算符优先级的问题,导致出错
命名约定
#undef - 用于移除一条宏定义
条件编译
常见的条件编译
#if与#endif是一对
写判断也是可以的~
多分支条件编译
判断是否被定义
嵌套指令
文件包含
防止头文件被多次包含
定义一次之后,就不会再定义了~
避免了出现多次定义同一个头文件导致的代码行数过多的情况~
另一种方法: