原创作者:郑同学的笔记
原创地址:https://zhengjunxue.blog.csdn.net/article/details/131690070
qq技术交流群:921273910
当你在编写 C++ 函数时,有时候你会需要处理可变数量的参数。C++ 中提供了 头文件,其中包含了用于处理可变参数的函数和宏。本教程将向你介绍如何使用 来编写可变参数的函数。
从【编译、链接、装载十五】系统调用与API——printf源码分析可知printf的源码如下。
wget http://mirrors.ustc.edu.cn/gnu/libc/glibc-2.28.tar.gz
glibc-2.28\stdio-common\printf.c
#include
#include
#include
#undef printf
/* Write formatted output to stdout from the format string FORMAT. */
/* VARARGS1 */
int
__printf (const char *format, ...)
{
va_list arg;
int done;
va_start (arg, format);
done = vfprintf (stdout, format, arg);
va_end (arg);
return done;
}
可变参数函数允许你在函数中接受不定数量的参数。C++ 使用 提供的函数和宏来访问这些参数。以下是可变参数函数的基本工作原理:
首先,我们需要引入 头文件,以便能够使用其中的函数和宏。在代码的开头添加以下语句:
#include
在函数定义中,将省略号(…)放在参数列表的最后一个参数之前,以声明可变数量的参数。例如:
void printValues(int count, ...);
以上代码定义了一个名为 printValues 的函数,它接受一个整数 count,以及可变数量的参数。
va_list 是一个类型,用于存储可变参数的信息。在函数内部,我们需要声明一个 va_list 类型的对象来处理参数。例如:
void printValues(int count, ...) {
va_list args;
// 其他代码
}
上述代码中,我们创建了一个名为 args 的 va_list 对象。
在访问可变参数之前,我们需要使用 va_start 宏对 va_list 对象进行初始化。va_start 宏需要两个参数:va_list 对象和最后一个固定参数的名称。例如:
void printValues(int count, ...) {
va_list args;
va_start(args, count);
// 其他代码
}
这样做会将 args 对象设置为可变参数的初始状态。
现在,我们可以使用 va_arg 宏按顺序访问每个可变参数。va_arg 需要两个参数:va_list 对象和参数的类型。以下是一个示例:
void printValues(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i) {
int number = va_arg(args, int);
// 使用 number 做进一步处理
}
// 其他代码
}
上述代码中,我们使用 for 循环和 va_arg 宏从 args 中获取了指定数量的整数参数。
请注意,我们需要根据参数的实际类型来选择正确的参数类型。此外,重复调用 va_arg 将按照参数的顺序依次访问每个可变参数。
在最后使用完可变参数后,我们应该使用 va_end 宏清理 va_list 对象。例如:
void printValues(int count, ...) {
va_list args;
va_start(args, count);
// 使用 va_arg 访问参数
va_end(args);
}
这样做会确保释放 va_list 对象所占用的资源,并使其处于正确的状态。
以下是一个完整的示例代码,演示了如何编写一个函数 printValues,并打印出参数的值:
#include
#include
void printValues(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i) {
int number = va_arg(args, int);
std::cout << "Number: " << number << std::endl;
}
va_end(args);
}
int main() {
printValues(4, 10, 20, 30, 40);
return 0;
}
在上述示例中,我们定义了一个 printValues 函数,它接受一个整数 count 和不定数量的参数。函数根据指定的数量打印出每个参数的值。
在 main 函数中,我们调用了 printValues 函数,并传递了一个整数和四个参数。函数会按照指定的数量打印出每个参数的值。
输出结果如下:
Number: 10
Number: 20
Number: 30
Number: 40
这就是使用 头文件来编写可变参数函数的基本步骤。你可以根据实际需求扩展和修改示例代码。
下面是一个完整的示例代码,演示了如何编写一个带有可变参数的函数,并打印出这些参数的值:
#include
#include
void printValues(const char* format, ...) {
va_list args;
va_start(args, format);
while (*format != '\0') {
if (*format == '%') {
format++;
switch (*format) {
case 'd': {
int value = va_arg(args, int);
std::cout << "Value: " << value << std::endl;
break;
}
case 'f': {
double value = va_arg(args, double);
std::cout << "Value: " << value << std::endl;
break;
}
case 's': {
const char* value = va_arg(args, const char*);
std::cout << "Value: " << value << std::endl;
break;
}
default:
break;
}
}
format++;
}
va_end(args);
}
int main() {
printValues("%d %f %s", 10, 3.14, "Hello");
return 0;
}
在上述示例中,我们定义了一个 printValues 函数,它接受一个格式字符串和不定数量的参数。函数根据格式字符串的指示,使用 va_arg 从 args 中按顺序获取每个可变参数,并将其打印出来。
在 main 函数中,我们调用了 printValues 函数,并传递了一个格式字符串和三个参数(整数、双精度浮点数和字符串)。函数会按照格式字符串中的指示打印出每个参数的值。
输出结果如下:
Value: 10
Value: 3.14
Value: Hello
当需要将格式化的字符串输出或存储到字符缓冲区时,可以使用 snprintf 和 vsnprintf 函数。
snprintf 函数是标准库中的一个函数,用于将格式化的字符串输出或存储到字符缓冲区中。它的原型如下:
int snprintf(char* buffer, size_t count, const char* format, ...);
与之类似,vsnprintf 是一个类似的函数,用于将可变参数列表格式化为字符串并存储到字符缓冲区中。其原型如下:
int vsnprintf(char* buffer, size_t count, const char* format, va_list arglist);
arglist 是一个 va_list 对象,需要使用 va_start 宏和 va_end 宏来初始化和清理。
这两个函数在处理可变参数列表时非常有用,可以方便地进行字符串格式化操作,并提供了一定的安全性,以避免字符缓冲区溢出的问题。
以下是一个示例,演示了如何使用 snprintf 和 vsnprintf 函数:
#include
#include
void formatString(char* buffer, size_t count, const char* format, ...) {
va_list args;
va_start(args, format);
// 使用 vsnprintf 将格式化的文本存储到临时缓冲区
char temp[100];
vsnprintf(temp, sizeof(temp), format, args);
// 使用 snprintf 将临时缓冲区的内容复制到目标缓冲区
snprintf(buffer, count, "%s", temp);
va_end(args);
}
int main() {
char buffer[100];
formatString(buffer, sizeof(buffer), "Hello, %s!\n", "World");
printf("%s", buffer);
return 0;
}
在这个示例中,我们定义了一个 formatString 函数,该函数使用 vsnprintf 将可变参数列表格式化为字符串,并将结果存储在临时缓冲区 temp 中。然后,我们使用 snprintf 将 temp 缓冲区的内容复制到目标缓冲区 buffer 中。
在 main 函数中,我们调用 formatString 函数,将格式化的字符串 “Hello, World!” 存储在 buffer 中,并用 printf 输出结果。