简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
本篇目的:C++之va_start、vasprintf、va_end应用总结。
在C/C++语言中,va_start
、vasprintf
和va_end
是与可变参数相关的函数。它们通常与stdarg.h
头文件一起使用。
va_start
函数:
va_start
函数用于初始化可变参数列表。它接受两个参数:第一个参数是一个va_list
类型的变量,第二个参数是最后一个固定参数的前一个参数的名称。va_list
类型变量初始化为指向可变参数列表的起始位置。vasprintf
函数:
vasprintf
函数用于将格式化的可变参数输出到动态分配的字符串中。char
指针的指针,第二个参数是一个格式化字符串。va_end
函数:
va_end
函数用于结束可变参数的获取。va_list
类型的变量。通常在需要处理可变参数的情况下,使用实现Printf风格的函数或者处理命令行参数时。
#include
#include
void sum(int count, ...)
{
va_list args;
int total = 0;
// 初始化可变参数列表
va_start(args, count);
// 遍历可变参数列表并求和
for (int i = 0; i < count; i++)
{
int num = va_arg(args, int);
total += num;
}
// 结束可变参数列表
va_end(args);
printf("Sum: %d\n", total);
}
int main()
{
sum(3, 1, 2, 3); // 输出 Sum: 6
return 0;
}
va_start
是一个宏,用于处理可变参数列表。它的原理是基于C语言的可变参数机制。
va_start
宏的工作原理如下:
首先,通过传入的参数列表的类型信息和格式化字符串来确定参数列表的起始位置。
然后,通过指针运算和类型大小来计算出参数列表中各个参数的位置。
最后,将参数列表位置信息保存在一个va_list
类型的变量中,供后续函数进行处理。
va_start
宏的实现通常依赖于编译器和操作系统的底层支持。它使用了一些机制来获取参数列表的信息,如栈帧结构、类型信息、指针运算等。
具体实现的细节可能因编译器和操作系统而异,但通常会涉及以下步骤:
获取栈帧指针:va_start
宏需要通过访问栈来获取参数列表的位置信息。它首先获取当前函数的栈帧指针,可以通过编译器提供的相关函数或底层汇编指令来实现。
计算参数列表位置:通过栈帧指针和参数类型大小,va_start
宏可以计算出参数列表中各个参数的位置。这通常涉及指针运算,根据参数类型大小来移动指针位置。
保存参数列表信息:va_start
宏将参数列表位置信息保存在一个va_list
类型的变量中,以便后续的函数进行处理。可以将栈帧指针和计算得到的参数列表位置信息存储在va_list
变量中。
va_start
宏使用一些编译器和操作系统提供的底层机制来实现可变参数的处理。具体实现可能会因编译器和操作系统的不同而异,也可能受到编译器的优化策略的影响。
#include
#include
char* format_string(const char* format, ...)
{
va_list args;
char* str;
// 初始化可变参数列表
va_start(args, format);
// 格式化字符串并存储到动态分配的字符串中
int length = vasprintf(&str, format, args);
// 结束可变参数列表
va_end(args);
printf("Formatted String: %s\n", str);
printf("String Length: %d\n", length);
return str;
}
int main()
{
char* result = format_string("Hello %s, your age is %d.", "John", 25);
// 输出 Formatted String: Hello John, your age is 25.
// 输出 String Length: 30
free(result); // 释放动态分配的字符串
return 0;
}
va_end
是一个宏,用于结束对可变参数列表的访问。它的原理是基于C语言的可变参数机制。
va_end
宏的工作原理如下:
首先,它接收一个va_list
类型的变量作为参数,该变量保存了参数列表的位置信息。
接着,通过一系列机制(如编译器和操作系统的底层支持)实现将参数列表进行清理和释放的操作。
最后,将va_list
类型的变量标记为无效,以确保之后对它的访问是无效的。
具体实现的细节可能因编译器和操作系统而异,但通常会涉及以下步骤:
清理参数列表:va_end
宏根据参数列表的位置信息,使用特定的机制将参数列表进行清理。它可能涉及释放资源、清理栈上的参数值等操作。具体的清理操作由编译器和操作系统提供的底层支持来实现。
使va_list
变量失效:为了确保在之后对va_list
变量的访问是无效的,va_end
宏将该变量标记为无效。这样可以避免误用已经结束的参数列表。
va_end
宏的实现依赖于编译器和操作系统的底层支持。具体实现的细节可能会因编译器和操作系统的不同而异。但无论实现细节如何,va_end
宏的目标都是确保正确清理和释放可变参数列表所占用的资源,并将va_list
变量标记为无效。
#include
#include
#include
#include
#include
using namespace std;
string AStringPrintf(const char *format, ...) {
va_list ap;
va_start(ap, format);
char *buffer;
int bufferSize = vasprintf(&buffer, format, ap);
va_end(ap);
if(bufferSize < 0) {
return string();
}
string result(buffer);
free(buffer);
buffer = NULL;
return result;
}
int main(){
char str[64]={1,2,3,5,6,7,8,9};
string buf = AStringPrintf(str);
printf("buf = %s\n",buf.c_str());
}
vsnprintf
函数接收一个格式化字符串和一个va_list
类型的参数列表。利用格式化字符串,它将参数列表中的数据转换为相应的字符串格式。
首先,vsnprintf
函数根据格式化字符串中的格式指示符,逐个读取参数列表的值,并根据指示符的要求对其进行格式化。
然后,vsnprintf
函数根据格式化的结果,将其写入到指定的缓冲区中。它会确保写入的数据不超过指定的缓冲区大小。
最后,vsnprintf
函数会在写入完成后,返回实际写入的字符数(不包括结尾的’\0’)。如果缓冲区大小不足以容纳格式化后的字符串,vsnprintf
函数会截断字符串,但仍然会返回实际要写入的字符数。
需要注意的是,由于vsnprintf
函数是经过格式化而得到的字符串的长度是不确定的,因此在使用之前需要分配足够的缓冲区来存储格式化后的字符串,以避免缓冲区溢出的情况发生。
vsnprintf
函数是一个用于以固定格式将可变参数格式化为字符串的函数。它将格式化的结果写入指定的缓冲区,并返回实际写入的字符数。这个函数在C++中可用于处理可变参数,并将其转换为字符串格式。
#include
#include
#include
void dynamic_print(const char* format, ...)
{
va_list args;
va_start(args, format);
char* dyn_str = NULL;
size_t str_length = 0;
// 计算动态生成字符串所需的长度
str_length = vsnprintf(NULL, 0, format, args);
// 为字符串动态分配内存
dyn_str = (char*)malloc(str_length + 1);
// 动态生成字符串
vsnprintf(dyn_str, str_length + 1, format, args);
printf("%s", dyn_str);
free(dyn_str);
va_end(args);
}
int main(){
int num1 = 10;
int num2 = 20;
dynamic_print("Sum: %d + %d = %d\n", num1, num2, num1 + num2);
return 0;
}