# 工欲善其事必先利其器-C语言拓展--嵌入式C语言(二)

本文深入探讨了C语言中的宏定义,从简单的#define开始,逐步讲解如何处理运算符优先级问题,以及如何利用语句表达式解决自增运算引起的错误。通过示例展示了如何利用typeof关键字实现类型安全的宏,以避免参数类型变化带来的问题。文章适合有一定C语言基础的读者,旨在提升对宏定义和类型安全的理解。
摘要由CSDN通过智能技术生成

工欲善其事必先利其器-C语言拓展–嵌入式C语言(二)

表达式、语句和代码块–>宏

前言

提起宏,脑子里第一时间想到的就是

#define PI 3.14

但是最近在看Linux内核代码的时候,我简直了,各种花里胡哨的宏定义,我只能说有点东西。

这里的宏加入了语句表达式,一下子宏就变得精彩了。

举个栗子–>请定义一个宏,求两个数的最大值。

合格

#define MAX(x,y) x > y ? x : y

那么我们来测试一下?

MAX(1,2)

MAX(2,1)

MAX(2,2)

MAX(1!=1,1!=2)

如,测试第4行语句,当宏的参数是一个表达式,发现实际运行结果为max=0,和我们预期结果max=1不一样。

这是因为,宏展开后,变成如下样子。

printf("max=%d", 1!=1 > 1!=2 ? 1!=1: 1!=2);

因为**比较运算符>的优先级为6,大于!=(优先级为7),**所以在展开的表达式中,运算顺序发生了改变,结果就和预期不一样了。

为了避免这种展开错误,我们可以给宏的参数加一个小括号(),防止展开后表达式的运算顺序发生变化。

#define MAX(x,y) (x) > (y) ? (x) : (y)

中等

是不是觉得上面的就不错了?

那么再来个测试

3+MAX(1+2)

这按说应该等于5,但是实际上等于1。经过上面你肯定猜到了是运算符优先级变化的问题,我们展开宏的时候。

因为运算符+的优先级大于比较运算符>,所以这个表达式就变为4>2?1:2。

于是这个时候我们继续修改,用小括号将宏定义包起来。这样避免当一个表达式同时含有宏定义和其他高优先级运算符时,破坏整个表达式的运算顺序。。

#define MAX(x,y) ((x)>(y) ? (x):(y))

到这里我们加了两次括号了

良好

是不是感觉自己又行了,别高兴太早哦。

整个栗子试试

i=2;
j=6;
MAX(i++,j++)

展开

((2++)>(6++) ? (2++):(6++))

结果–>7,有没有选6的小伙伴

这是因为变量i和j在宏展开后,做了两次自增运算,导致打印出的i值为7。

在C语言编程规范中,使用宏时一般是不允许参数变化的。

但是总有些调皮鬼,要这么写应该怎么办呢?

–>语句表达式

我们可以使用语句表达式来定义这个宏,在语句表达式中定义两个临时变量,分别来暂时存储i和j的值然后使用临时变量进行比较,这样就避免了两次自增、自减问题。

看这个有点绕,看看代码

#define MAX(x, y)({ \
    int _x = x;     \
    int _y = y;     \
    _x > _y ? _x : _y;\
})

定义了2个局部变量_x、_y来存储宏参数x和y的值,然后使用_x和_y来比较大小,这样就避免了i和j带来的2次自增运算问题。

将参数与符号分开了

优秀

上面这个级别其实已经很nice了,再内核代码中我也看到了一些这样的,原来是这样的。

不过我们需要再进一步的提高自己的要求。

上面的宏只能对整形的数据进行操作,但是当不是整形难道要重新的定义吗?

那可不行哦,来来来看看下面。

#define MAX(type, x, y)({\
  type _x = x;          \
  type _y = y;          \
  _x > _y ? _x : _y;    \
})

MAX(int, i++, j++);
MAX(float, 3.14, 3.15);

在这里我们通过一个type这不就解决了,其实宏这种东西就是字符串,我觉得就是字符串的拼接替代,这样是不是会有帮助理解一点,如果没有,当我没说。

牛啊牛啊

但是我们这个type是不是感觉有点太突兀了,每次还的专门整个变量类型,如果我不知道呢?有没有想到能自动获取类型的。

这里有办法了—想起这个没–>typeof

#define max(x, y)({   \
  typeof(x) _x = (x); \
  typeof(y) _y = (y); \
  (void) (&_x == &_y);\
  _x > _y ? _x : _y ; })

有点疑惑为什么有个 (void) (&_x == &_y);\ 这个玩意?

这是用来给用户警告的,对于不同类型的指针进行比较,编译器会发出警告,提示你。

warning:comparison of distinct pointer types lacks a cast

其次这个数的比较,但是这个比较的结果用不上,可能会报warning,这个时候加一个(void)后,这个警告就pass了。(因为这个宏是发挥了作用的哦,宏在这里进行了比较呢)

内核中我看到了大量的这样的语句表达式,刚刚开始看我都问自己这还是我曾经见过的宏定义吗?

在Linux内核中,max_t和min_t的宏定义,就使用了语句表达式。

这下你知道了撒,其实就是我们常见宏的升级版本。

[学习资料]:《嵌入式C语言自我修养:从芯片、编译器到操作系统》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

TrustZone_Hcoco

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

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

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

打赏作者

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

抵扣说明:

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

余额充值