目录
- 一. 预定义符号
- 二. #define
- 1.#define定义常量
- 2.#define定义宏
- 3.带有副作用的宏参数
- 4.宏替换的规则
- 5.宏和函数的对比
一. 预定义符号
%s _ _FILE_ _ //文件
%s _ _ DATE_ _ //日期
%s _ _ TIME_ _ //时间
%d _ _ LINE_ _ //行号
%d _ _ STDC_ _ //如果编译器支持 ANSI C,那么该值为1,
//否则未定义
二. #define
1.#define定义常量
define name stuff
#define定义常量在预处理阶段被替换成对应的内容(stuff)
// name:符号名
// stuff:符号内容
举个例子:
#define MAX 1000
#define reg registe
//使用reg 等同于使用 registe,还更为简洁
#define forever for(;;)
//初始化
//调整
//判断都可以省略不写
//但是判断不写,条件会恒为真,会造成死循环
int main()
{
printf("%d\n", MAX);
MAX直接被替换为1000
return 0;
}
2.#define定义宏
#define name(parament-list) stuff
name:符号名
parament-list:是由逗号隔开的参数表,他们有可能出现在stuff中
stuff:符号内容 == 表达式
注意:
parament-list的左括号必须紧挨到name,不然parament-list会被识别为stuff中的内容
举个例子:
#define SQUARE(x) x*x
int main()
{
int a = 10;
printf("%d\n",SQUARE(a));//100
printf("%d\n",SQUARE(a+1));//21
return 0;
}
这里的 x = 10,1010 = 100
**a+1是直接进行替换,是a+1a+1 = 2*a + 1 = 21
注意:
宏替换时不要吝啬括号,尽量能加括号的就加括号
所以加括号可以避免符号运算中出现不可预料的结果
那么这题正确是:#define SQUARE(x) ((x) * (x))
3.带有副作用的宏参数
宏的参数带有副作用就可能出现不可预料的结果
a + 1;//没有副作用
a++;//具有副作用
MAX可以证明带有副作用的宏
#define MAX(a,b) ((a>b) ? (a) : (b))
int main()
{
int a = 1;
int b = 2;
int c = MAX(a++,b++);
printf("%d %d %d",a,b,c);
// a = 2 b = 4 c = 3
return 0;
}
正确的写法:
4.宏替换的规则
1.在调用宏的时,首先对参数进行检查,检查是否有宏定义的符号,如果有,他们首先被替换
2.替换文本随后被插入到程序中原来文本的位置。
对于宏,参数名被他们的值所替换
3.最后再次对结果文件进行扫描,检查它是否还有#define定义的符号。如果是,就重复上述处理过程
注意:
1.宏参数和#define定义中可以出现其他#define定义的符号,但对于宏不能出现递归
#define MAX(a,MAX(2,3))//不是递归,是MAX的参数
#define MAX(x,y) MAX(x,y)//不能出现递归
//宏的内部调用了宏(表达式部分调用了宏)
2.当预处理器搜索#define出现的符号时,字符串常量并不被搜索
#define M 10
#define MAX(a,b) ((a>b) ? (a) : (b))
MAX(M,2);//M会被替换成10
printf("M = %d");//字符串常量不会被替换
5.宏和函数的对比
1.宏的优点:
通常被用于简单的运算
执行一条和函数有同样功能的语句,速度快,效率高
宏只有执行运算的时间,宏不存在内存的栈区静态区堆区,宏是不占用内存空间的
宏的参数无类型,所以宏可以进行任何类型的计算,是直接进行替换的
宏的参数可以出现类型:
#define MALLOC(num, type)\ // \为续行符,可以连接下一行
(type)malloc(num*sizeof(type))
...
//使⽤
MALLOC(10, int); //类型作为参数
//预处理器替换之后:
(int)malloc(10*sizeof(int));
2.宏的缺点:
宏会增加代码的长度,宏不能进行递归等等
3. 函数的优点:
函数会将值算好,才传参过去
4.函数的缺点:
函数的执行操作比较复杂,在反汇编中执行长度比较长
函数只能求特定类型的大小的运算等等