不清不楚之C语言中##__VA_ARGS__与__VA_ARGS__

文摘   2024-08-15 21:15   广东  


正文

     

大家好,我是bug菌~
最近在开发过程中又玩起了C语言的可变参数,在资源受限的MCU平台上,一般不太建议使用可变参数或者相应标准库函数如printf等,以免编译进去后导致程序代码段瞬间变大很多,当然有些简化版本的lib,不过也相当废资源,不过现在MCU的性能越来越卷,大部分项目都是资源过剩。
不过话说回来,C语言的可变参数用起来还挺顺手,像嵌入式经常打印的日志,为了更好的可移植性通常会进行封装,今天就不再赘述可变参数的语法了,大家感兴趣可以翻阅公众号往期文章,今天bug菌仅聊聊##__VA_ARGS__与__VA_ARGS__这对可变参数宏,相信大家在日常的编程中接触得倒不多,不过在大型开源软件中还是屡有见到,那么下面带大家分析分析:

1

__VA_ARGS__介绍

__VA_ARGS__ 是C语言中的一个预定义宏,用于处理可变数量的参数列表。通常用在宏定义中,以便宏能够接受不定数量的参数,并将它们作为整体处理。

在C语言中,使用函数可以接受可变数量的参数,例如printf和fprintf。然而,在宏定义中,参数数量通常是固定的。为了能够定义可以处理不同数量参数的宏,C99标准引入了__VA_ARGS__。下面的例子也都是在C99标准下编译运行。

__VA_ARGS__表示所有在宏调用中传递的额外参数。它可以放在宏定义的参数列表的末尾,用于接收任意数量的额外参数,比如:

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


解析:

  • DEBUG_LOG 是一个宏,接受至少一个参数 fmt(格式化字符串),后面可以是任意数量的参数。

  • __VA_ARGS__ 表示可变参数列表,在宏展开时会被替换为传递给 DEBUG_LOG 宏的所有实际参数。

示例:

#define DEBUG_LOG(fmt, ...) \
    printf("[%s:%d] " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)


DEBUG_LOG("Hello, %s! The answer is %d\n""world"42);


在这个调用中,"Hello, %s! The answer is %d\n" 是格式化字符串fmt,"world" 和 42 是额外的参数。这些参数会被依次传递给 printf 函数。__VA_ARGS__ 必须总是与宏定义中的省略号 ... 一起使用。省略号...用于指示宏可以接受可变数量的参数。在宏定义中,__VA_ARGS__ 可以单独使用(如果没有额外参数时),也可以与其他参数一起使用。

2

##在前面有啥用?

大家在了解__VA_ARGS__时,一定会看到有些地方在该宏定义前使用 ## 运算符来处理可变参数,如:

#define DEBUG_LOG(fmt, ...) \
    printf("[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)


其中这里的##运算符主要是用于连接左侧的符号(通常是逗号)和右侧的参数,从而确保宏展开时语法正确。

对于如下使用可变参数:

 DEBUG_LOG("Value of x: %d"42);

__VA_ARGS__与##__VA_ARGS__是没有太大区别的,且都能编译通过,打印输出相同的结果。

然而当可变参数为空时,如下:

DEBUG_LOG("Program starting...");

在C99编译器下,无##修饰的宏定义DEBUG_LOG 则会编译失败,而存在##修饰的宏##__VA_ARGS__ 处理为空的可变参数列表,防止在宏展开时出现不必要的逗号,从而使得编译通过。

最后

      好了,今天就跟大家分享这么多了,如果你觉得有所收获,一定记得点个~

bug菌唯一、永久、免费分享嵌入式技术知识平台~

推荐专辑  点击蓝色字体即可跳转

☞  MCU进阶专辑 

☞  嵌入式C语言进阶专辑 

☞  “bug说”专辑 

☞ 专辑|Linux应用程序编程大全

☞ 专辑|学点网络知识

☞ 专辑|手撕C语言

☞ 专辑|手撕C++语言

☞ 专辑|经验分享

☞ 专辑|电能控制技术

☞ 专辑 | 从单片机到Linux


最后一个bug
一个嵌入式技术进阶公众号,定期分享C语言,C++、MCU(如stm32等)、DSP、ARM、嵌入式Linux等“独门”软件设计技巧和知识归纳总结,同时分享应用程序设计、物联网、滤波及控制算法推导和仿真设计等嵌入式硬核知识技巧!欢迎大家关注!
 最新文章