文章目录

  • 1.stdarg.h
  • 2.##__VA_ARGS__的使用

1.stdarg.h

简介

  • stdarg 由 standard argument 简化而来,该头文件的主要目的为让函数能够接受可变参数。
  • 该头文件中声明了一个类型 va_list 和三个宏函数 va_start,va_arg 和 va_end。

数据类型(Types):

数据类型	
va_list	用来保存宏 va_arg 与宏 va_end 所需信息。

宏函数(Macro functions):

原型:void va_start (va_list ap, paramN);
功能:初始化一个可变参数列表
参数:第一个参数 ap 接受一个 va_list 变量,第二个参数 paramN 接受函数传入参数中的可变参数前的最后一个有名字的参数。

原型:type va_arg (va_list ap, type);
功能:获取可变参数列表中的下一个参数
参数:第一个参数 ap 是 va_list 变量,第二个参数 type 指明下一个参数的类型。

原型:void va_end (va_list ap);
功能:结束使用可变参数列表
参数:ap 接受一个结束访问的 va_list 变量。

原型:void va_copy (va_list dest, va_list src);
功能:产生一个可变参数列表的副本
参数:第一个参数 dest 为目标可变参数列表,第二个参数 src 是源可变参数列表。
  • eg:
#include <stdio.h>
#include <stdarg.h>

double average(int n,...){
    double sum = 0;
    va_list args; // 声明一个 va_list 类型的变量 args
    //va_list v2;
    va_start(args, n); // 通过调用 va_start 来初始化这个 args
    //va_copy(v2, args); // 复制操作
    for(int i = 0; i < n; i++){
        sum += va_arg(args, double); // 通过调用 va_arg 获取下一个参数
    }
    va_end(args); // 释放 va_list 变量
    return sum / n;
}

int main(){
    printf("%.2lf", average(4, 1.0, 2.0, 3.0, 4.0));
    return 0;
}
  • 测试:
jiwangreal@ubuntu:~/code/test$ ./build/bin/testarvg 
2.500000

2.##__VA_ARGS__的使用

#:

  • 用来把参数转换成字符串;
#include <iostream>
 
#define LOG(x) do { printf("%s=%d\n",#x,x); }while(0)
 
int main()
{
    int score = 96;
    LOG(score);
    LOG(6);
    
    getchar();
    return 0;
}
  • 测试:

    ##:
  • 用于将带参数的宏定义中将两个子串(token)联接起来,从而形成一个新的子串;但它不可以是第一个或者最后一个子串。所谓的子串(token)就是指编译器能够识别的最小语法单元;
  • eg:
#include <iostream>
 
#define LOG(x) log##x()
 
void logA(){
    printf("log func A \n");
}
 
void logB(){
    printf("log func B\n");
}
 
int main()
{
    LOG(A);
 
    getchar();
    return 0;
}
  • 测试:

##VA_ARGS

  • 用于在宏替换部分中,表示可变参数列表;
    用于在宏替换部分中,表示可变参数列表;
  • eg:
#include <stdio.h>

#define LOG2(...) printf("123+%s=%d\n", ##__VA_ARGS__) //该宏定义GCC、MSVC下均未报错
 
int main()
{
	// LOG("3", 123 + 3);
	LOG2("123", 123);
 
	return 0;
}
  • 测试:
123+123=123
  • eg:如果可变参数被忽略或为空,## 操作将使预处理器(preprocessor)去除掉它前面的那个逗号.
#include <stdio.h>

#define LOGFUNC2(fmt,...) (printf(fmt" line:%d - %s/%s   \n",##__VA_ARGS__,__LINE__,__TIME__,__DATE__));

int main()
{
    //可变参数
    LOGFUNC2("i am C++ :%d name:%s age:%d",112,"C语言教程",18);// ok

    //字符串常量
    LOGFUNC2("i am C++ ");// ok
}
  • 测试:
jiwangreal@ubuntu:~/code/test$ ./build/bin/testarvg 
i am C++ :112 name:C���Խ̳� age:18 line:8 - 07:19:33/Jul  7 2022   
i am C++  line:11 - 07:19:33/Jul  7 2022
  • eg:C 库函数 - vsprintf()
#include <stdio.h>
#include <stdarg.h>

char buffer[80];
int vspfunc(char *format, ...)
{
   va_list aptr;
   int ret;

   va_start(aptr, format);
   ret = vsprintf(buffer, format, aptr);
   va_end(aptr);

   return(ret);
}

int main()
{
   int i = 5;
   float f = 27.0;
   char str[50] = "runoob.com";

   vspfunc("%d %f %s", i, f, str);
   printf("%s\n", buffer);
   
   return(0);
}
  • 测试:
5 27.000000 runoob.com