0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何使用宏偷梁换柱

454398 来源:alpha007 作者:alpha007 2022-11-15 17:33 次阅读

有些时候,一些原本的函数功能可能并不是我们想要的,于是就想着修改函数,或者再封装一层函数。

比如对一个函数包装:

void func()

{

printf("hello/n");

}

// 包装函数

void my_func()

{

printf("add/n");

func();

}

打印效果如下:

每打印一个 hello 前面都会增加一个 add。

这样确实能达到效果,但是因为多调用了一次函数,所以性能会部分下降,同时需要更大的栈空间,那么是否有一种更好的方式去达到相同的目的呢?

有的,那就是使用宏进行偷梁换柱,达到狸猫换太子的目的。

我们以打印函数为例,对它进行偷梁换柱。

一般的打印函数只会打印我们输入给它的参数,却无法打印额外的信息,比如时间戳、函数名、文件名、行号等。简单一点,假如我们希望在打印我们的消息前,能添加时间戳和函数名,又该如何做呢?

简单且易理解的偷梁换柱如下:

// 定义我们自己的打印函数格式

#define OSPREY_LOG(fmt, ...) rt_kprintf("<%08d>[%s] "fmt"/r/n",/

rt_tick_get(), __FUNCTION__, ##__VA_ARGS__)

#undef printf // 使 printf 在下面失去效用

// 重新定义,此时下面的所有 printf 是一个宏,而不是函数

#define printf(fmt, ...) OSPREY_LOG(fmt, ##__VA_ARGS__)

void osprey_task(void *parameter)

{

uint32_t nbr = 0;

while(1)

{

printf("hello, Osprey %u", nbr++);

rt_thread_delay(1);

}

}

原本我们的代码里面使用的是 printf 进行打印,但自己比较懒,不想每次换平台的时候都修改打印函数(比如 RT-Thread 使用 rt_kprintf 打印),或者怕替换的时候操作失误,那么此时就可以使用这个技巧了。

我们先定义出我们自己的打印格式(关于这个,鱼鹰会专门写一篇笔记介绍如何设计一个简单实用的日志打印框架,里面会详细介绍这些内容,目前暂时拿来用就行),这个格式包含了时间戳信息、函数名信息。

之后,使用 #undef 这条预编译指令取消掉 printf 的作用域,接下来的代码将不再调用标准库的函数,而是使用我们自己定义的宏函数 printf,所以我们使用 #define 重新定义 printf。

也就是说,#undef printf 指令后面的代码将使用 宏函数 printf ,而不是标准库函数 printf,这是一道分水岭。

接下来看看打印的效果如何:

可以看到,在我们的 “hello,Osprey”之前,打印了我们需要的时间戳和函数名信息,完美!

通过这些信息,我们就可以知道打印的消息是在什么时候打印的,又是在哪个函数中打印的,定位问题将更加方便(当然你也可以加入文件名和行号,看自己的需要了)。

通过以上三行代码,我们成功且高效的完成了函数的再次封装,并且除了这些代码,不需要对后面的代码做任何修改,万一平台换了,也只需要修改这些代码就行。

现在再来一个稍微难理解一点的。

既然前面的代码可以替换 printf 打印函数,那么我们会想,是否可以替换 rt_kprintf 本身呢?

也就是说本来我的代码就是用 rt_kprintf 函数打印的,我们是否可以对它进行封装呢?
所以接下来的代码应运而生:

// 定义我们自己的打印函数格式

#define OSPREY_LOG(fmt, ...) rt_kprintf("<%08d>[%s] "fmt"/r/n",/

rt_tick_get(), __FUNCTION__, ##__VA_ARGS__)

#undef rt_kprintf // 使 rt_kprintf 在下面失去效用

// 重新定义,此时下面的所有 rt_kprintf 是一个宏,而不是函数

#define rt_kprintf(fmt, ...) OSPREY_LOG(fmt, ##__VA_ARGS__)

void osprey_task(void *parameter)

{

uint32_t nbr = 0;

while(1)

{

rt_kprintf("hello, Osprey %u", nbr++);

rt_thread_delay(1);

}

}

当你测试后,你会发现,打印效果和前面的代码等同,也就是说,通过三条代码,成功将 rt_kprintf 狸猫换太子了。

其实当你理解了 #undef 和 #define,上面代码是不难理解的,#undef 取消了 rt_kprintf 的定义,而 #define 又重新定义了 rt_kprintf,所以接下来的:

rt_kprintf("hello, Osprey %u", nbr++);

被替换成了 :

rt_kprintf("<%08d>[%s] "hello, Osprey %u"/r/n",/rt_tick_get(), __FUNCTION__, nbr++)

因为 rt_kprintf 函数已经有了,最后编译、链接的时候也就能顺利通过了,爽!

当然,有时候版本发布的时候,我们发现不再需要打印函数了,那么我们只要使用如下方式即可消除打印(文件开头添加即可,注意 //):

这个骚操作,你学会了吗?


审核编辑 黄昊宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 函数
    +关注

    关注

    3

    文章

    3868

    浏览量

    61309
收藏 人收藏

    评论

    相关推荐

    C语言中的

    定义是我们C语言学习中非常重要的内容。一些基础的用法大家都比较清楚了,我们简单总结一下。1.定义的格式为:#define 标识符 字符串。2.定义属于预处理命令,在编译过程中的预处理阶段处理
    发表于 12-13 15:32

    offsetof与container_of详解

    offsetof与container_of详解 1.offsetof与container_of1.1、由结构体指针进而访问各元素的原理通过结构体整体变量来访问其中各个元素,本
    发表于 10-13 16:35

    扩展问题

    MPLAB IDIDV3.65和XC8HI,“扩展工具”是一个方便的工具来查看在项目文件中的扩展(右键单击并选择导航/视图扩展)。不幸的是,我发现了一个问题:当我在文件中更改
    发表于 04-14 09:57

    什么是看了就知道

    本文介绍了一些示例,但 DV 工程师可以根据项目要求和可重用目的创建和使用类似的
    发表于 12-11 07:08

    什么是

    什么是示例的应用
    发表于 12-15 07:34

    如何设计调试

    前言借调试的设计,梳理下的用法重定向printf打印嵌入式设备基本会配置RS232串口作为调试IO接口,假设底层串口单字节输出函数为SERIAL_PutChar(),利用fputc()和fputs()重定向printf函数void fputc(int byte, FI
    发表于 12-15 06:13

    C语言中的是什么

    第五章 性能优化5.1 使用定义  在C语言中,是产生内嵌代码的唯一方法。对于嵌入式系统而言,为了能达到性能要求,是一种很好的代替函数的方法。  写一个"标准"MIN ,这个
    发表于 12-15 08:20

    如何设计调试

    如何设计调试
    发表于 12-24 06:37

    华为荣耀9曝光:麒麟965+3D玻璃机身,跟小米6死磕到底!

    面图上看出外观和荣耀8具有比较高的类似度,不过荣耀9的机身选用的是3D玻璃的规划,之前的小米5即是选用的这个玻璃机身,深受我们喜欢。华为这次也是也是要偷梁换柱。并且值得一提的是,荣耀9取消了后置指纹,那么肯定会选用前置指纹了,不知道荣耀系列的前置指纹有会是如何了。
    发表于 04-18 08:59 1330次阅读

    美国5G是水货吗 AT&T偷梁换柱冒用5G

    著名的人民大学国家关系学院金灿荣教授在评论中美关系时,忍不住吐槽说:美国有个水货5G知道吧?
    的头像 发表于 04-30 10:41 2997次阅读

    特斯拉偷梁换柱 用户真的是天使

    如果要在光怪陆离的电动汽车市场找两个人物,特斯拉和蔚来是“不三”的选择,因为它们因电动而创造了汽车的全新未来。特斯拉因电动而智能,封闭式前脸造型、超简约的内饰设计以及面向未来的最终自动驾驶系统,引领全球智能汽车发展。蔚来因为电动而豪华,换电模式、NOMI交互机器人以及极致而全面的用户服务体系,成为中国豪华汽车的领军人物。特斯拉和蔚来在中国市场的关系,以即将上市Model Y 和EC6为代表,重复着“外国的月亮更圆”的历史。
    发表于 03-07 11:30 672次阅读

    价值380余万元人民币的芯片被盗:里应外合,偷梁换柱

    继3000片iPhoneX芯片被盗、一企业百万元芯片被盗等案件后,又一起巨额芯片盗窃案在深圳发生。 据@深圳南山公安 微博消息,近日,南山警方快速侦破一起团伙盗窃案,涉案价值380余万元人民币,抓获盗窃嫌疑人3名,追回被盗芯片。 据了解,当时深圳南山区一科技公司委托徐先生报警称:该公司尚未投入市场的芯片竟然已被人使用,通过检查清点库存情况,发现50344片存储芯片被盗,总价值380多万元人民币。 在目前晶圆代工、封装产能紧缺涨价的周期里
    的头像 发表于 12-11 10:12 2206次阅读

    网易云音乐再度回应酷狗:偷梁换柱

    本周网易云音乐与酷狗音乐之间的争论成为业界关注的焦点。
    的头像 发表于 02-04 15:44 2334次阅读

    室外12芯单模光缆架空管道光纤线缆 欧孚光缆厂家定做

    室外12芯单模光缆、欧孚光缆厂家定做 光缆厂家有很多,但是肯定光缆厂家之间是有不同的,有的偷工减料,偷梁换柱,质量也是参差不齐,以次充好。不同光缆厂家用的材料不同,成本不同,价格肯定是不同的,像我
    发表于 10-26 13:32 860次阅读

    一款与PMC232-S16A引脚兼容的TX8C1010S016B单片机

    的引脚兼容,可以免去考虑到测试认证的烦恼,方案商的测试验证做得好,还可以起到偷梁换柱的功效,在产品的核心部件停产的情况下,依然可以延续生产。
    的头像 发表于 10-20 09:30 428次阅读
    一款与PMC232-S16A引脚兼容的TX8C1010S016B单片机