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

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

3天内不再提示

使用宏定义来封装一个宏打印函数

Q4MP_gh_c472c21 来源:嵌入式大杂烩 作者:嵌入式大杂烩 2022-04-18 14:32 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

宏打印函数

在我们的嵌入式开发中,使用printf打印一些信息是一种常用的调试手段。但是,在打印的信息量比较多的时候,就比较难知道哪些信息在哪个函数里进行打印。

特别是对于异常情况的打印,我们需要快速定位到异常情况的位置。

这时候我们可以使用宏定义来封装一个宏打印函数,这个宏打印函数可以显示打印信息所在的文件、行数、函数名等信息。如:

#defineDBG_PRINTF(fmt,args...)
{
printf("<>",__FILE__,__LINE__,__FUNCTION__);
printf(fmt,##args);
}

使用范例:

c69d846a-bed7-11ec-9e50-dac502259ad0.png

c6af7eea-bed7-11ec-9e50-dac502259ad0.png

可见,使用方法与printf的使用方法一样,而且每条打印语句开头都会打印调试信息所在的文件名、行号、函数名信息,方便我们查找一些调试信息。

其中,__FILE____LINE____FUNCTION__这三个宏是编译器内置宏定义,分别代表调试信息所在文件、行号、函数。

除此之外,常用的宏还有:__DATE____TIME__,分别代表当前的编译日期与时间。如:

DBG_PRINTF("Compile Time: %s  %s
", __DATE__, __TIME__);

c6bb87da-bed7-11ec-9e50-dac502259ad0.png

第二条printf中的##符号是为了处理args不代表任何参数的情况。如:

DBG_PRINTF("Hello world");

当不加##符号是,以上宏的第二条语句被拓展为:

printf("Helloworld
",);

可见,多出了一个逗号,这个逗号是多余的。

加上##符号后,以上宏的第二条语句被拓展为:

printf("Helloworld
");

这才是我们想要的结果。其实这些结果我们通过查看预处理文件可以清晰的知道:

c6c4f50e-bed7-11ec-9e50-dac502259ad0.png

c6ce38b2-bed7-11ec-9e50-dac502259ad0.png

c6e0a24a-bed7-11ec-9e50-dac502259ad0.png

最后需要注意的是,这个DBG_PRINTF还是与printf不一样的。DBG_PRINTF宏是两条语句的组合,无返回值;而printf的原型是:

intprintf(constchar*__format,...)

但是我们一般都很少使用printf的返回值,所以DBG_PRINTF的用法与printf函数基本一致。

打印调试宏开关

通常情况下,一些打印调试信息只是在我们调试阶段需要的,在程序发布阶段是不需要的。

所以,为了避免打印调试信息带来的资源开销,我们可以把这些打印调试语句给注释掉。

一种方法是逐句进行注释,这是一种比较低效的方法。比较高效的方法就是添加调试宏开关,利用条件编译来选择打印/不打印调试信息。

比如我们可以把上面的代码改造为:

#defineDEBUG1

#ifDEBUG
#defineDBG_PRINTF(fmt,args...)
{
printf("<>",__FILE__,__LINE__,__FUNCTION__);
printf(fmt,##args);
}
#else
#defineDBG_PRINTF(fmt,args...)
#endif

根据DEBUG宏的值来选择对应的打印宏函数。当DEBUG的值为1时启动相关的打印调试语句,DEBUG的值为0时则关闭打印调试语句。

这样我们就可以很方便的通过设置DEBUG宏的值来启动与关闭我们整个工程的DBG_PRINTF打印调试信息。

do{}while(0)

其实,上面我们封装的打印宏DBG_PRINTF还有一点缺陷,比如我们与if、else使用的时候,会有这样的一种使用情况:

c6e8e662-bed7-11ec-9e50-dac502259ad0.png

此时会报语法错误。为什么呢?

同样的,我们可以先来看一下我们的demo代码预处理过后,相应的宏代码会被转换为什么。如:

c6f062a2-bed7-11ec-9e50-dac502259ad0.png

这里我们可以看到,我们的if、else结构代码被替换为如下形式:

if(c)
{/*.......*/};
else
{/*.......*/};

显然,出现了语法错误。if之后的大括号之后不能加分号,这里的分号其实可以看做一条空语句,这个空语句会把if与else给分隔开来,导致else不能正确匹配到if,导致语法错误。

为了解决这个问题,有几种方法。第一种方法是:把分号去掉。代码变成:

c6fa21d4-bed7-11ec-9e50-dac502259ad0.png

第二种方法是:在if之后使用DBG_PRINTF打印调试时总是加{}。代码变成:

c7086424-bed7-11ec-9e50-dac502259ad0.png

以上两种方法都可以正常编译、运行了。

但是,我们C语言中,每条语句往往以分号结尾;并且,总有些人习惯在if判断之后只有一条语句的情况下不加大括号;而且我们创建的DBG_PRINTF宏函数的目的就是为了对标printf函数,printf函数的使用加分号在任何地方的使用都是没有问题的。

基于这几个原因,我们有必要再对我们的DBG_PRINTF宏函数进行一个改造。

下面引入do{}while(0)来对我们的DBG_PRINTF进行一个简单的改造。改造后的DBG_PRINTF宏函数如下:

#define DBG_PRINTF(fmt, args...)  
do
{
    printf("<> ", __FILE__, __LINE__, __FUNCTION__);
    printf(fmt, ##args);
}while(0)

这里的do...while循环的循环体只执行一次,与不加循环是效果一样。并且,可以避免了上面的问题。预处理文件:

c713cc2e-bed7-11ec-9e50-dac502259ad0.png

我们的宏函数实体中,while(0)后面不加分号,在实际调用时补上分号,既符合了C语言语句分号结尾的习惯,也符合了do...while的语法规则。

使用do{}while(0)来封装宏函数可能会让很多初学者看着不习惯,但必须承认的是,这确确实实是一种很常用的方法。

STM32的HAL库中搜索while(0):

c71d7bac-bed7-11ec-9e50-dac502259ad0.png

c732df88-bed7-11ec-9e50-dac502259ad0.png

Linux源码中搜索while(0):

c743e38c-bed7-11ec-9e50-dac502259ad0.png

可见,在实际应用中,do{}while(0)用的很多。

#运算符与##运算符

这两个运算符之前也有分享过,这里顺便也提一下。

#号作为一个预处理运算符,可以把记号转换成字符串。

例如,如果A是一个宏形参,那么#A就是转换为字符串"A"的形参名。这个过程称字符串化(stringizing)。以下程序演示这个过程:

c74fdd9a-bed7-11ec-9e50-dac502259ad0.jpg

c75744e0-bed7-11ec-9e50-dac502259ad0.jpg

##运算符可以把两个记号组合成一个记号。以下程序演示这个过程:

c7642e58-bed7-11ec-9e50-dac502259ad0.jpg

c76e4a46-bed7-11ec-9e50-dac502259ad0.jpg

这个运算符用得很多。如:

c7792664-bed7-11ec-9e50-dac502259ad0.png

END 审核编辑 :李倩

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

    关注

    3

    文章

    4422

    浏览量

    67847
  • 编译器
    +关注

    关注

    1

    文章

    1672

    浏览量

    51909

原文标题:这几个宏技巧,绝对实用!

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    【快速温变循环】快速温变循环试验箱的“循环”之道:展科技如何定义循环”

    在军工、航天、汽车电子等高端制造领域,快速温变循环试验是验证产品可靠性的核心手段。然而,“循环”到底如何定义?是简单的升降温,还是对速率、驻留时间、温变曲线精度、循环重复性的严苛约束?广东
    的头像 发表于 04-16 09:38 263次阅读
    【快速温变循环】快速温变循环试验箱的“循环”之道:<b class='flag-5'>宏</b>展科技如何<b class='flag-5'>定义</b>“<b class='flag-5'>一</b><b class='flag-5'>个</b>循环”

    低成本键盘旋钮开源项目介绍

    办公切软件、调参数太繁琐?创作时控笔刷 / 缩放总找快捷键?商用键盘价格高,还难适配个性化操作需求?想自制键盘,却遇设计复杂、组装难度高的问题?
    的头像 发表于 03-25 11:09 521次阅读

    微科技首家欧洲全资子公司正式成立

    在国家积极鼓励企业“走出去”及共建“路”倡议的宏大背景下,国内功率半导体领域的领先企业——江苏微科技股份有限公司(以下简称“微科技”)今日宣布,其首家欧洲全资子公司 MacM
    的头像 发表于 03-04 11:06 648次阅读

    龙芯中科与杉科技完成产品适配互认证

    近日,龙芯中科技术股份有限公司与杭州杉科技股份有限公司完成基于龙芯3C6000处理器平台对杉分布式存储系统的适配与性能验证。测试结果表明,杉分布式存储产品在龙芯3C6000平台上运行稳定、性能优异,标志着双方在国产自主计算
    的头像 发表于 01-23 17:08 978次阅读
    龙芯中科与<b class='flag-5'>宏</b>杉科技完成产品适配互认证

    C语言中实现函数的三种方式

    1. 函数介绍 函数,即包含多条语句的定义,其通常为某
    发表于 12-29 07:34

    微科技举斩获两项重磅行业大奖

    聚力创新动能,破局产业难题,领航技术前沿!近期深圳半导体与电源技术领域盛会密集,微科技携旗下子公司上海微爱赛半导体有限公司(以下简称“微爱赛”)强势亮相。凭借突出的技术实力与产品性能,
    的头像 发表于 12-19 17:22 1000次阅读
    <b class='flag-5'>宏</b>微科技<b class='flag-5'>一</b>举斩获两项重磅行业大奖

    泰科技与ADI正式签署合作备忘录

    近日,南京泰半导体科技股份有限公司(以下简称“泰科技”)与全球领先的高性能半导体公司ADI正式签署合作备忘录,双方将在半导体测试与精密信号测量领域展开持续深度合作,共同推动高性能测试系统的技术创新与市场应用落地。
    的头像 发表于 12-02 09:09 1680次阅读

    C语言拼接运算符典型使用

    在C语言中,##运算符(称为[size=16.002px]标记拼接运算符)用于定义中将两标记(token)拼接成新的标记。它在预处理
    发表于 11-20 08:27

    齐光多种不同封装贴片发光管点亮多元应用新视界

    在当今快速发展的科技时代,贴片发光管凭借其体积小、功耗低、亮度高、色彩丰富等优点,广泛应用于各个领域。齐光多种不同封装贴片发光管点亮多元应用新视界,为现代生活和工业生产带来了诸多便利与创新。那么
    的头像 发表于 10-17 16:51 1561次阅读
    <b class='flag-5'>宏</b>齐光多种不同<b class='flag-5'>封装</b>贴片发光管点亮多元应用新视界

    RT_USING_TIMER_SOFT定义是否定要开启?

    定义 :RT_USING_TIMER_SOFT 请问:如果没有使能软件定时器的定义,只在创建定时器时,通过RT_TIMER_FLAG_SOFT_TIMER是否可以创建
    发表于 09-29 07:11

    SConscript结果与rtconfig.h中定义相反,是什么原因呢?

    当我在rtconfig.h中把定义注释时,添加了构建 当我取消定义注释时,反而排除了构建 SConscript结果与rtconfig.h中
    发表于 09-23 06:01

    C语言中的内联函数

    在C编程中,内联函数都用于避免函数调用的开销并编写可复用的逻辑部分,但它们在工作方式和安全性方面存在显著差异。
    的头像 发表于 07-25 15:10 2067次阅读
    C语言中的内联<b class='flag-5'>函数</b>与<b class='flag-5'>宏</b>

    Vicor助力发打造主动悬架电源系统

    厦门发电声股份有限公司(发)打造业内性能卓越的主动悬架电源系统,旨在将长期以来仅见于豪华车型的功能引入中端车型。发成功突破困扰知名汽车技术供应商几十年的技术瓶颈,在满足主动悬架系统对尺寸、重量及瞬态性能的严苛需求的同时,兼
    的头像 发表于 06-04 15:24 1327次阅读

    微科技2025供应商大会成功举办

    近日,以“协同·精进·共赢”为主题的微科技2025供应商大会在常州隆重召开。来自全国各地的专家和供应商伙伴们齐聚堂,与微科技共同回顾合作成果,展望未来蓝图。
    的头像 发表于 05-30 15:33 1074次阅读

    女高知创业20载 忆峥嵘岁月稠—芯微科技吴环芝专访

    KinghelmSlkor大冲啦!编者按芯微科技大冲历史悠久,是南头半岛乃至深圳西部地区最古老的村落之,“冲”意为“通行的大道”或“重要的地方”。本期,金航标记者走进“中国硅谷”深圳南山区高新
    的头像 发表于 05-20 16:38 898次阅读
    女高知创业20载 忆峥嵘岁月稠—<b class='flag-5'>宏</b>芯微科技吴环芝专访