重新认识--宏

版权声明:允许转载,请注明文章出处 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.icat 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);

宏表达式中不能出现递归定义,这点区别于函数,因为宏只做简单的文本替换,且只替换一次,如果出现递归定义,就会无法被完全替换,导致后续编译时原宏名被当作函数。

猜你喜欢

转载自blog.csdn.net/Vickers_xiaowei/article/details/86490564