版权声明:允许转载,请注明文章出处 https://blog.csdn.net/Vickers_xiaowei/article/details/86490564
文章目录
声明:代码演示均在Centos7系统使用Vi编辑器和gcc编译器实现
一、宏的优点
#define MAX(a, b) ((a)>(b)?(a):(b))
高效
函数调用是都会带来很大的系统开销,宏在预处理阶段完成,不需要调用堆栈等系统开销。
便捷
- 函数有类型限制,宏没有类型限制。
- 当在一段程序中反复出现某一特定数量(比如三子棋棋盘的宽度和高度),我们只需要将这个数值定义为一个显示常量,当需要改动时候,只需修改一处就可以将程序中的该数量全部修改。
二、宏定义
1、语法
#define name stuff
举几个栗子
#define ROW 11
#define reg register //为register创建一个简短的名字
#define do_forever for(;;)
宏名原则:全大写,函数名原则:驼峰原则。宏的作用范围是从定义出开始到程序结束。
2、宏不是语句----宏定义不加;
vi define.c
#include<stdio.h>
#define MAX 100;
int main()
{
for (int i = 0; i < MAX; i++)
printf("%d",i);
return 0;
}
这段代码在预处理阶段不会出错,gcc-E define.c -o defien.i
,cat define.i
,你可以明显看到这个宏替换语句后加;
造成的语法错误,而语法错误在编译阶段才会被检查出来。
3、宏参数列表中()
的使用
宏参数要带()
#include<stdio.h>
#define MUL(x) x*x
int main()
{
printf("%d",MUL(10+1));
return 0;
}
预期的结果是121,实际结果21,在宏替换过程中被替换成了10+1*10+1
,这明显不对,为了防止这种情况,需要对宏参数加()
#include<stdio.h>
#define MUL(x) (x)*(x)
int main()
{
printf("%d",MUL(10+1));
return 0;
}
宏表达式求值要加()
求两个数中较大的那个数
#include<stdio.h>
#define MAX(x,y) (x)>(y)?(x):(y)
int main()
{
printf("%d",5*MAX(10,20));
return 0;
}
预期结果是100,实际结果是10,宏替换之后5*(10)>(20)?(10):(20)
,5*10=50,50>20?=10:20,结果是10。为了防止这种情况,宏的结果也要带()
。
4、#和##
使用#
表示,把一个宏参数替换成对应的字符串。例如上式中的Max(a,b)
被替换成了(((a)>(b))?(a):(b))
,从而实现了两个数的比较。
#include<stdio.h>
#define Test(num,value) do{sum##num=value} while (0)
int main()
{
Test(2,30);
return 0;
}
使用##
,起到将符号左右两部分连接的作用,这样连接的结果必须是合法的标识符,否则结果就是未定义的。
5 、宏可以在命令行定义
#include <stdio.h>
int main()
{
int array [ARRAY_SIZE];
int i = 0;
for(i = 0; i< ARRAY_SIZE; i ++)
{
array[i] = i;
}
for(i = 0; i< ARRAY_SIZE; i ++)
{
printf("%d " ,array[i]);
}
printf("\n" );
return 0;
}
可以实现一个根据实际需要去设定数组容量的数组。
6、undef取消宏定义
作用范围有define到undef位置。
三、宏和函数的对比
1、宏的缺点
- a、宏要求代码短小,否则每次调用宏都会展开,会造成空间冗余。
- b、宏是没法调试的。
- c、宏由于类型无关,也就不够严谨。
- d、宏可能会带来运算符优先级的问题,导致程容易出现错。
2、宏参数可以是类型名,函数不可以
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MALLOC(num, type) (type *)malloc(num * sizeof(type))
int main()
{
int*p=MALLOC(10,int);
return 0;
}
四、暗藏杀机的宏
1、带副作用的宏参数
x++; 带副作用
x+1; 不带副作用
#include<stdio.h>
#define Max(a,b) (((a)>(b))?(a):(b))
int main()
{
int x = 3;
int y = 7;
int z = Max(x++, y++);
printf("x:%d\ny:%d\nz:%d\n",x,y,z);
return 0;
}
经过宏替换之后,
2、宏中不容小视的空格
#define f (x) ((x)-1)
的意思是f
代表(x) ((x)-1)
,宏和参数列表的括号之间不能有空格。
3、宏不是函数----宏不能递归
宏参数和#define定义中可以出现#define定义的变量。但是宏不能出现递归。
#define Func(n) ((n>0) ? (Func(n-1)+1) : 0)
int j=Func(50);
被预编译后:
int j=((50>0) ? (Func(50-1)+1) : 0);
宏表达式中不能出现递归定义,这点区别于函数,因为宏只做简单的文本替换,且只替换一次,如果出现递归定义,就会无法被完全替换,导致后续编译时原宏名被当作函数。