本文章介绍一下C语言中一些跟可变参数相关的宏及其用法
这里写目录标题
- 引言
- va_list
- va_start
- va_arg
- va_end
- 以上函数的联合使用样例:
- vsnprintf
- __VA_ARGS_
引言
C语言中有很多的带有可变参数的函数,例如printf函数,它的定义其实是类似这样子的
void printf(char *format,...);
其中format为格式化的数据,后面三个点是占位符,用来表示可变参数列表
如果我们想自定义带有可变参数的函数的话,format(格式化数据)必须是函数中参数列表的最后一个固定参数,接下来介绍几个跟可变参数列表有关的宏
宏和函数不同,宏在预处理阶段就会被展开,其实现由编译器提供,通常会包含在相应的标准库头文件中。
va_list
#include<stdarg.h>
va_list args;
va_list数据类型代表可变参数列表,我们可以通过这个数据类型,来使用可变参数列表或者访问可变参数列表中的每一个元素,这个类型一般作为其他函数的参数来使用.
va_start
void va_start(va_list ap, last_arg);
用作初始化可变参数列表
其中 ap 是一个 va_list对象,表示可变参数列表
last_arg 是带有可变参数的函数中的最后一个固定参数
va_arg
type va_arg(va_list ap, type);
用来访问可变参数列表中的某一个参数,并将可变参数列表的指针往后面移动一位
具体的使用例子:
获取可变参数列表中第一个参数,参数类型为int
int num = va_arg(args,int);
获取可变参数列表中第一个参数,参数类型为char *
char *str = va_arg(args,char*);
va_end
void va_end(va_list ap);
结束对可变参数的访问
以上函数的联合使用样例:
void my_printf(char *format, ...) {va_list args;va_start(args, format); // 初始化可变参数列表char *ptr = format;while (*ptr != '\0') {if (*ptr == '%') {ptr++; // 移动到格式字符if (*ptr == 'd') {int num = va_arg(args, int); // 获取 int 类型参数printf("%d", num);} else if (*ptr == 's') {char *str = va_arg(args, char*); // 获取 char* 类型参数printf("%s", str);} else {printf("Invalid format specifier!"); // 不支持的格式符号}} else {putchar(*ptr); // 普通字符直接输出}ptr++;}va_end(args); // 结束可变参数列表
}
vsnprintf
这个是一个函数,而不是一个宏
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
str 指定将格式化数据放入的字符串
size 缓冲区大小
format 格式化数据
ap 可变参数列表
这个函数和snprintf函数非常类似,都是把格式化的数据放入指定长度的字符串中,但是区别是snprintf函数的最后一个参数是三个点的可变参数列表(. . .),而vsnprintf函数的最后一个参数是 va_list类型的可变参数列表
具体使用方式
#include <stdio.h>
#include <stdarg.h>void formatString(char *buffer, size_t size, const char *format, ...) {va_list args;va_start(args, format);vsnprintf(buffer, size, format, args);va_end(args);
}int main() {char buffer[20];int num = 42;formatString(buffer, sizeof(buffer), "The answer is: %d", num);printf("Buffer content: %s\n", buffer);return 0;
}
_VA_ARGS
如果我们想在C语言中定义有可变参数的宏的话,就需要使用这个宏
//最简单的定义
#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_前面加上 ##,这样就会去掉前面的逗号,防止编译错误.
#include<stdio.g>
#define my_print1(...) printf(__VA_ARGS__)
int main()
{ int a=1,b=2;my_print1("%d%d",a,b);
}