在 C/C++ 之中,有时会遇到一些疑难杂症,但大多数情况下不会触发它,但如果触发它导致崩溃,的确会让人心态很炸裂。
我们知道我们想要提供C语言接口的动态参数传递给其它C动态参数函数,会通过va_list 来转发调用,这个在C语言之中是不存在问题的,但是在 C++ 之中它可能存在一些问题,这是因为 C++ 语言之中函数的调用协议之间是不确定的。
它可能是__fastcall、__thiscall、__stdcall 这些,而C语言函数调用协议是 __cdecl,这就带来潜在的不确定风险性。
即这段代码从语义执行上似乎都没有出现过任何问题,但是运行一段时间之后就导致崩溃,同时在C语言可变参数之中使用 STL容器(如 std::string)也会导致莫名其妙的崩溃,但在绝大多数时间内它都被正确执行。
解决这类问题在 C/C++ 语言之中,我们应当首选通过 C/C++ 动态参数模板来实现,例如:我们期望对于 snprintf 的动态参数转发,并且返回std::string字符串,正确做法与不正确做法。
正确:(一半,开O3后有一定崩溃风险,看脸运行时间多长)
std::string test(const char* format, ...) noexcept {char buffer[8096];va_list ap;va_start(ap, format);vsnprintf(buffer, sizeof(buffer), format, args);va_end(ap);return buffer;}
正确:
template <class... A>std::string test(const char* format, A&&... args) noexcept {char buffer[8096];snprintf(buffer, sizeof(buffer), format, std::forward<A&&>(args)...);return buffer;}
错误:
auto printfn = [](const char* format, ...) noexcept{va_list ap;va_start(ap, format);std::string st = test(format, ap);va_end(ap);};
即自己在 C/C++ 中声明了:
std::string test(const char* format, va_list args) noexcept;
调用 vsnprintf 函数传递C语言可变参数列表。
在封装C语言可变参数 ...(语法)方式在封装传递,100%会遭遇较为快速的程序崩溃,但也不是立马崩溃,一般性调试期间基本不会崩。
但也不意味着完全不崩,只是要等它重复次数足够多,就是需要一定时间,这并非内存损坏问题。
在 C/C++ 语言之中,必须通过可变参数模板方式来传递可变参数列表,否则都是不安全,存在不缺行崩溃风险的。