宏:va_list、## 、…、arg …、##__VAL_ARGS

文章目录

  • 一 ##和#
  • 二 …、可变参数宏 \_\_VA\_ARGS\_\_ 和 ##\_\_VA\_ARGS\_\_
  • 三 va_list
  • 四 典型用法
  • 参考资料

一 ##和#

#指的是把参数转换成字符

#define FUN(X) (printf("%s=%d\n",#X,X)) /* #用来把参数转换成字符 */

int test(int argc, char ** argv)

{
 int a = 1;
 int b = 2;
 
 FUN(a);
 FUN(b);
 FUN(a+b);
 
 return 0;
}

/*************程序输出结果:******************
a=1
b=2
a+b=3

*****************************/**

##指的是把两个语言符号组合成单个语言符号


#define XNAME(n) x##n /* ## 这个运算符把两个语言符号组合成单个语言符号*/

#define PXN(n) printf("x"#n" = %d\n",x##n)

int main(int argc, char ** argv)

{

int XNAME(1) = 10886; /*宏展开就是:x1 = 10086*/

PXN(1); /*宏展开就是:printf("x1 = %d\n",x1) */

return 0;
}

二 …、可变参数宏 __VA_ARGS__ 和 ##__VA_ARGS__

__VA_ARGS__是一个可变参数的宏,定义时宏定义中参数列表的最后一个参数为省略号...,在实际使用时会发现有时会加##,有时又不加。

//最简单的定义
#define my_print1(...) printf(__VA_ARGS__)

//搭配va_list的format使用
#define my_print2(format, ...) printf(format, __VA_ARGS__)
#define my_print3(format, ...) printf(format, ##__VA_ARGS__)

__VA_ARGS__宏前面加上##的作用在于,当可变参数的个数为0时,这里printf参数列表中的的 **##会把前面多余的","去掉** ,否则会编译出错,建议使用后面这种,使得程序更加健壮。

三 va_list

VA_LIST的用法:

(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;

(2)然后用VA_START宏初始化变量刚定义的VA_LIST变量;

(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);

(4)最后用VA_END宏结束可变参数的获取。

#include 
#include 
#include 
#define log(format,...)  write_log(format,__VA_ARGS__)

char *m_buf;

void write_log(char* format,...)
{
 m_buf = new char[1000];
 va_list valst;
 //将传入的format参数赋值给valst,便于格式化输出
 va_start(valst, format);
 //调用vsnprintf拷贝进入缓冲区
 int m = vsnprintf(m_buf, 1000, format, valst);
 m_buf[m + 1] = '\0';
 va_end(valst);
}
int main()
{
 log("abc%d", 123);
 printf("%s", m_buf);
}

注意:

使用VA_LIST应该注意的问题:

(1)因为va_start, va_arg,

va_end等定义成宏,所以它显得很愚蠢,可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能地识别不同参数的个数和类型.

也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的.

(2)另外有一个问题,因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码。

(3)由于参数的地址用于VA_START宏,所以参数不能声明为寄存器变量,或作为函数或数组类型。

四 典型用法

#include 

#define DEBUG1(fmt,) \
do \
{ \
printf(fmt, ##__VA_ARGS__); \
} \
} while(0)

#define DEBUG2(fmt, args …) \
do \
{ \
printf(fmt, ##args); \
\
} while(0)

#define DEBUG3(fmt,) \
do \
{ \
printf("File:%s, Line:%s, "fmt"", __FILE__, __LINE__, ##__VA_ARGS__); \
\
} while(0) 


int main(int argc, char **argv)
{
  printf("hello world.1\n");

  DEBUG1("hello world.2 %d, %d\n", 1, 2);

  DEBUG2("hello world.3 %d %d %d\n", 1, 2, 3);

  DEBUG3("hello world %d %d\\n", 1, 2);
  
  return 0;
  
}

参考资料

[1] va_list与__VA_ARGS__ https://blog.csdn.net/qq_36459662/article/details/106988773

[2] https://blog.csdn.net/weixin_35615495/article/details/117065976

[3] https://blog.csdn.net/weixin_35615495/article/details/117065976

你可能感兴趣的:(C/C++,嵌入式,c++,开发语言)