程序环境和预处理
一、翻译环境和执行环境
翻译环境:在这个环境中源代码被转换为可执行的机器指令
执行环境:用于实际执行代码
具体什么意思我们通过画图来解释
1.翻译环境
翻译环境分为两步,编译和链接
那么编译和链接是什么呢,同样以图来说明
那么问题又来了,编译和链接的过程中发生了什么
由于编译和链接内部需要Linux环境深入了解,这里直接上定义
2.执行环境
简述一下程序执行的过程
1.程序必须载入内存中.
在有操作系统的环境中:一般由操作系统完成
在独立的环境中:程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存完成
2.程序执行便开始,调用main函数
3.开始执行程序代码.这个时候程序将使用一个运行的堆栈(stack)(堆栈就是栈),存储函数的局部变量和返回地址.
程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值.
4.终止程序.正常终止main函数,也可能是意外终止.
以上
二、预处理详解
1.预定义符号
1 | __FILE__ //进行编译的源文件 %s |
2.#define定义宏
#define允许把参数替换到文本中
勤加()
3.#和##
①#
#可以把参数替换到字符串中
引出一下常见情况
1 | void print(int x) |
所以我们使用宏
首先我们要知道
1 | printf("halo"); |
1 |
|
有
1 | //格式不同的处理 |
注意:#不能直接用在printf中,只能在宏内使用
②##
直接举个例子
1 |
|
4.宏和函数的取舍
属性 | #define定义宏 | 函数 |
---|---|---|
代码长度 | 每次使用时,宏代码都会被插入程序中.除了非常小的宏除外,程序的长度会大幅提升 | 函数代码只出现于一个地方,每次调用这个函数时,都调用那个地方的同一份代码 |
执行速度 | 更快 | 存在函数的调用和返回的额外开销,所以相对较慢 |
操作符优先级 | 宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写时多些括号 | 函数参数只在函数调用的时候求值一次,它的结果值传递给函数.表达式的求值结果更容易预测 |
带有副作用的参数 | 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果 | 函数传参只在传参的时候求值一次,结果更容易控制 |
参数类型 | 宏的参数与类型无关,只要对参数的操作时合法的,它就可以使用于任何参数类型 | 函数的参数与类型有关,如果参数的类型不同,就需要不同的函数 |
调试 | 宏是不方便调试的 | 函数是可以逐语句调试的 |
递归 | 宏不能递归 | 函数可以递归 |
以上
5.undef
该指令可以移除一条宏定义
比如说
1 |
6.条件编译
先上一个例子
1 |
|
#ifdef 后跟宏名称
#if 后跟常量表达式
同样都是以#endif作为结尾
同样的还有#else 、#elif其后面跟的都是常量表达式
1 | int main() |
也有
#ifndef 作用与 #ifdef相反
#if defined() 括号内加入宏名,作用与 #ifdef相同
也可以#if !defined(),作用与 #ifdef相反