博主介绍:程序喵大人
- 35 - 资深C/C++/Rust/Android/iOS客户端开发
- 10年大厂工作经验
- 嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手
- 《C++20高级编程》《C++23高级编程》等多本书籍著译者
- 更多原创精品文章,首发gzh,见文末
- 👇👇记得订阅专栏,以防走丢👇👇
😉C++基础系列专栏
😃C语言基础系列专栏
🤣C++大佬养成攻略专栏
🤓C++训练营
👉🏻个人网站
背景
最近遇到了个奇怪的问题,同样的代码,在Windows 下正常运行,在iOS下必现crash。
异常代码如下:
cpp
std::string StringPrintf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
char* buffer = nullptr;
const size_t size = std::vsnprintf(nullptr, 0, format, ap) + 1;
buffer = new char[size];
std::vsnprintf(buffer, size, format, ap);
va_end(ap);
std::string result(buffer);
delete[] buffer;
return result;
}
经过分析定位后发现,这里重复使用了va_list并且在vsnprintf后还继续使用了ap,进而导致的crash。
通过查看文档:https://port70.net/\~nsz/c/c11/n1570.html#7.21.6.8

这里明确说明,arg在vsnprintf后,会变成不确定的状态。所以才有了在Windows上可以正常运行,在iOS上会异常退出的问题。
如何解决这个问题?
标准做法是使用va_copy复制一份va_list,如下:
cpp
std::string StringPrintf(const char* format, ...)
{
va_list ap, ap_copy;
va_start(ap, format);
va_copy(ap_copy, ap);
const int32_t size = std::vsnprintf(nullptr, 0, format, ap) + 1;
va_end(ap);
if (size <= 0) {
return "";
}
char* buffer = new char[size];
std::vsnprintf(buffer, size, format, ap_copy);
va_end(ap_copy);
std::string result(buffer);
delete[] buffer;
return result;
}
以前都是直接使用的三方库StringPrintf,而没有自己实现。这也算是使用vsnprintf过程中遇到的一个小坑,在此分享记录一下。
码字不易,欢迎大家点赞,关注,评论,谢谢!