宏的理解和陷阱

函数宏是一种在编译时展开的宏定义,它可以简化代码,提高运行速度,但也有副作用,如类型安全问题和意外的语义改变。使用时需注意避免空格影响、未正确括号导致的计算错误,以及逗号表达式的使用来确保语句的正确性。此外,示例展示了如何改进函数宏以避免语法错误。
摘要由CSDN通过智能技术生成

函数宏

 什么是函数宏?

是函数?

它说:我是宏,也是函数,但我是你得不到的药(哼!)

下面是一串简单的代码,利用函数sqr_int和sqr_double对x和y求平方

int main()
{
	int x=0;//记得初始化哦
	double y = 0;
	int ret1 = 0;
	double ret2 = 0;
	ret1 = sqr_int(x);
	ret2 = sqr_double(y);
}

 但是但是!!!

                                                                                                         好麻烦

 不同类型的变量需要不同的函数,接二连三地写出这种功能相近、名称又相似的函数,程序中就会充斥着这些似是而非的函数。

蓝廋想哭。。。

我就是大名鼎鼎的宏函数,看看我的本领吧!

#define sqr(x) x*x
int main()
{
	int x=0;//记得初始化哦
	double y = 0;
	int ret1 = 0;
	double ret2 = 0;
	ret1 = sqr(x);
	ret2 = sqr(y);
}

 我是光我是风,我是唯一的神话。

函数和函数宏的区别

运行过程区别:

        优点:函数式宏sqr是在编译时展开并填入程序的,因此只要是能用双目运算符*进行乘法计算的数据类型,都能使用函数式宏。
                   而函数定义则需为每个形参都定义各自的数据类型,返回值的类型也只能为一种。就这一点而言,函数较为严格。

                   函数为进行了一些复杂处理,如:参数传递(将实参的值复制到形参)函数调用函数返回操作(程序流程的控制),返回值的传递

                   函数式宏所做的工作只是宏展开填入程序,并不进行上述处理

综上: 根据以上特征,函数式宏或许能使程序的运行速度稍微提高一点,但是程序自身却有可能变得臃肿(如果宏展开后的表达式很复杂,那么在使用到它的所有地方都会填入这些复杂的表式)。

快乐吧唧一下,没有了

 函数宏的副作用

 都说是药三分毒,我也有几分毒性在身上哦...

 记得(食用)使用时避开陷阱

 辅药一  

        如果在宏名称sqr和紧邻其后的“(”之间插入空格,进行如下宏定义

#define sgr(x) ((x)*(x))

        则sqr就会被编译器当作对象式宏,即程序中的 sgr 都会被代换为(x)((x)*(x))。
        我们在定义函数式宏时必须注意不要误将空格写入宏名称和“(”之间。

  辅药二

  以下是计算二值之和的函数式宏

#define sum of(x,y) x+ y

我们使用下述语句来调用这个宏。

z=sum of(a,b)*sum of(c,d);

宏展开后的表达式不尽如人意。z=a+b*c+d;
保险起见,我们在宏定义时将每个参数以及整个表达式都用()括起来就不会出错了。

#define sum of(x,y) ((x) + (y))

这样表达式就能正确展开了。z=((a)+(b)) *((c) + (d));

 辅药三

sqr(a++)展开后为((a++) * (at+))

每次展开,a 的值都会自增两次。在不经意间表达式被执行了两次

但函数不会,是由于其运行特征

高级一点的函数宏

#include<stdio.h>
#define puts_alert(str)   { putchar(\a'); puts(str);}
int main()
{    
    int n;
    printf("请输入一个整数:");
    scanf("%d",&n);
   
    if(n)
        puts_alert(这个数不是0。");
    else
        putsalert(这个数是0。");
    return 0;
}

函数式宏putsalert的定义是在puts 函数显示字符串str 时响铃。不过,这个程序在编译时会出错,不能运行。
main函数的if语句展开后如图8-2所示。if语会在第一个复合语)处结束,这时因为的 puts_alert(这个数不是0。");会被视为空语句。因此编译器会认为“没有 if,为何出现了else”

改良后的代码

#include<stdio.h>
#define puts_alert(str)   (putchar(\a'); puts(str);)
int main()
{    
    int n;
    printf("请输入一个整数:");
    scanf("%d",&n);
   
    if(n)
        puts_alert(这个数不是0。");
    else
        putsalert(这个数是0。");
    return 0;
}

细心的大家应该(没)发现,doge

答案就是逗号表达式。

函数式宏的展开

if (n)
    (putchar('\a'),puts("这个数不是0。"));一表达式语句

else
    (putchar(\a), puts("这个数是0。"));-表达式语句

如果宏定义中要代换两个以上的表达式,则使用逗号运算符连接,使其在语法上构成一个表达式。
补(逗号表达式):

对于使用逗号运算符的逗号表达式“a,b”,会按顺序判断表达式a和b。对左侧的表达式a仅进行判断,判断结果会被省去。而对右侧的表达式b进行判断所得到的类型和值,就是逗号表达式“a,b”的类型和值。例如,的值为3、的值为5时,若运行x=++i,++j;则1和都会递增,递增后的值6会被赋给x。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值