C++变量参数和 vsprintf
C++ Variable Arguments and vsprintf
我正在尝试为cstdio
中的标准sprintf
函数编写一些包装器。但是,我在运行程序时遇到了一些奇怪的行为和访问冲突崩溃。我已经简化了问题并在下面的代码中重现了它:
#include <string>
#include <cstdio>
#include <cstdarg>
std::string vfmt(const std::string& format, va_list args)
{
int size = format.size() * 2;
char* buffer = new char[size];
while (vsprintf(buffer, format.c_str(), args) < 0)
{
delete[] buffer;
size *= 2;
buffer = new char[size];
}
return std::string(buffer);
}
std::string fmt(const std::string& format, ...)
{
va_list args;
va_start(args, format);
std::string res = vfmt(format, args);
va_end(args);
return res;
}
int main()
{
std::string s = fmt("Hello %s!", "world");
printf(s.c_str());
return 0;
}
此代码在 vfmt
中调用 vsprintf
时会产生内存访问冲突。但是,当我将fmt
的功能签名从fmt(const std::string& format, ...)
更改为fmt(const char* format, ...)
时,我不再崩溃,一切都按预期工作。究竟为什么会这样?
为什么将format
参数的类型从const std::string&
更改为const char*
可以解决问题?还是看起来只是解决了?
不能使用引用类型作为参数来va_start。这就是为什么更改为char*
有效,因此离开string
但没有&
也是如此。使用引用会破坏为了获得可变数量的参数而完成的魔术。
请参阅是否有使用带有引用参数的 varargs 的陷阱。
你不能
那样做。 我的意思是,你说的版本"有效"。
vsprintf
不允许您检测传入的缓冲区何时太小,因为它不知道它有多大。 它会很乐意覆盖缓冲区后面的任何对象。 这可能会导致访问冲突,它可能会在以后的某个时候使您的程序崩溃,它可能会生成一封电子邮件给您的母亲,并附有不雅的图片。 这是未定义的行为。 重新分配和重试循环是无用的。
vsnprintf
有更好的运气,如果您的库提供它,它确实知道缓冲区有多大。
相关文章:
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 使用指向成员的指针将成员函数作为参数传递
- C++变量参数和 vsprintf
- C++,vsprintf 处理不断变化的参数数量和大幅面字符串