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

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

3天内不再提示

怎么利用C可变参数和宏定义来实现自己的日志系统

汽车电子技术 来源:IOT物联网小镇 作者:道哥 2023-02-14 13:50 次阅读

嵌入式应用的开发过程中,日志系统是非常重要的!

特别是在生产环节出现了偶发性的、与当前的执行环境相关的bug的时候,

如果没有日志系统来追踪问题,很难进行问题重现。

因此,实现一个自己的日志系统是很有帮助、很必要的。

在软件模型上,一般是把日志系统编译成库文件。

应用程序直接调用库中提供的API接口函数,即可记录日志信息

那么实现自己的日志系统需要有3个问题需要处理:

(1)日志API函数的设计。

(2)日志信息的缓存。

(3)日志信息的持久化,也就是写入到本地文件系统。

这篇文章主要说明第一个问题:日志API函数的设计。

先上代码:

图片

图片

测试

图片

图片

知识点

1.字符串字面量的拼接

C语言中,字符串的拼接有很多种方法:memcpy,strcpy,strcat,sprintf等等。

在代码19行,使用了C语言中的字符串字面量拼接的方式,把 " %s:%d(%s) \"" format "\"\\n"3个字符串拼接成一个字符串。

补充一下:

在日志系统代码中,有些地方需要格式化字符串。

使用sprintf是最方便的,但是也是效率最低的!

也可以利用一些第三方的库来实现字符串格式化,比如:fmtlib,facebook 的 folly format,google的 Abseil StrFormat。

当然,最好的方式是自己实现格式化特定类型的数据,可以显著的提高日志系统的吞吐量,下一篇文章再说说这部分代码。

2.可变参数

大家都知道,printf函数就是通过可变参数机制来实现的。

可变参数可以这样定义和使用:

(1)不带参数名

图片

(2)带参数名

图片

20行代码用 __VA_ARGS__ 来代表宏定义参数中的三个点(...),也就是可变参数。



再来说说“##”。

如果调用:debug2("code = %d", 100); 这样调用没有问题。

如果调用:debug2("hello"); 这里调用时,在format后面没有传入任何参数,那么就会编译错误,因为在宏替换之后变成了 printf("hello",),第一个参数之后多了一个逗号,因此报错。

如果调用:debug3("hello, world!"); 这样就没有问题,因为debug3中在可变参数__VA_ARGS__的前面有“##”,当编译器发现没有传入参数时,会自动把format后面的逗号去掉,所以编译OK。

3.宏定义中的#和##

#的作用就是在预处理的时候,把宏参数进行“字符串化”,例如:

图片

##的作用就是在预处理的时候,把两个宏参数进行“粘合”,例如:

图片

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

    关注

    0

    文章

    7

    浏览量

    6953
  • 生产
    +关注

    关注

    0

    文章

    119

    浏览量

    13967
  • 嵌入式应用
    +关注

    关注

    0

    文章

    57

    浏览量

    18385
收藏 人收藏

    评论

    相关推荐

    可变参数函数的实现原理

    ,或者其它方式。在C语言标准头文件stdarg.h里面已经为可变函数定义了几个,使用这些也可以实现
    发表于 10-21 22:18

    C语言定义技巧

    C语言定义技巧
    发表于 03-01 21:58

    C语言定义中#和##的作用

    定义的递归展开。可以通过中间的转换的实现参数
    发表于 08-23 18:22

    C语言中的

    。还有一些任务根本无法用函数实现,但是用定义却很好实现。比如参数类型没法作为参数传递给函数,但
    发表于 12-13 15:32

    C语言——可变参数问题.

    来区别不同函数参数的调用,但它还是不能表示任意数量的函数参数。   问题:printf的实现   请问,如何自己实现printf函数,如何处
    发表于 04-20 15:17

    C语言之预处理

    :#define 符号名(参数表) 表达式如:#define MIN(x,y) (((x)51.h的头文件,而你的源代码目录里也有一个你自己写的at89c51.h头文件,那么使用尖括
    发表于 06-03 17:23

    有关于定义的问题,涉及##和#

    想通过定义实现,如下面格式#define link(arg) RCC_APB2Periph_##arg返回的结果为RCC_APB2Periph_GPIOC,以方便在时钟使能函数中使
    发表于 04-20 23:33

    请问C语言不同的条件怎么使用不同的定义

    碰到一个问题:需要根据一个参数的值来使用不同的定义,但是之前好像没见过if(xxx == x){#define xxxx}这种语句,有没有哪位大神有好的办法实现这个功能呢
    发表于 10-08 09:30

    XC32编译器是否支持中的可变参数列表?

    我试图在实现可变参数列表,但是得到以下错误:error:u VA_ARGS_只能出现在C99可变
    发表于 03-16 10:24

    C语言中可变参数定义

    C语言的可变参数定义。//可变参数用...表示
    发表于 07-14 07:43

    嵌入式log打印格式输出有哪些技巧?

    嵌入式log打印格式输出技巧Log 信息格式条件编译可变参数C标准中一些预定义格式输出16
    发表于 10-28 08:06

    C语言中的是什么

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

    单片机中的日志系统是如何实现的?

    系统等级函数主要由xLogInt()和xLog()函数通过定义实现,最终用户操作调用的也就是日志系统
    发表于 03-11 10:29

    讲讲调试程序的重要方法—打印日志

    大不相同,其开发环境中往往不会提供日志接口。单片机的驱动库往往只提供基础的操作外设的接口,如uart,i2c,spi,而不提供高层次的SDK。这就需要我们自己设计。单片机
    发表于 06-20 17:14

    如何才能在51系统下使用类似printf这样的可变参数的子函数呢?

    增加3个字节的地址,这样就没用办法使用“...”,传递参数了,如何才能在51系统下使用类似printf这样的可变参数的子函数呢?
    发表于 10-30 08:27