我正在尝试在两个函数之间转发非模板变量参数。这些函数都不属于我,所以我无法更改它们的签名。我使用
va_args
来实现此目的,但不幸的是我的解决方案在 MSVC 下无法正常工作。可能是由于堆栈重叠,我最终得到了从堆栈中选取的随机值。
这是重现我的问题的最小示例。函数
funcA
和 funcB
与我原来问题中的函数具有相同的签名。
#include <stdarg.h>
int funcA(int a, void* b, ...)
{
va_list args;
va_start(args, b);
auto value = a + va_arg(args, int);
va_end(args);
return value;
}
int funcB(int a, void* b, ...)
{
va_list args;
va_start(args, b);
auto value = funcA(a, args);
va_end(args);
return value;
}
int main() {
return funcB(2, nullptr, 163);
}
GCC 可能的输出:
Program returned: 165
可能的输出MSVC:
Program returned: 7731509
您可以从这里运行此代码https://godbolt.org/z/Mjc8E3onW
上述解决方案在 GCC 下可以正常工作并符合预期,但在 MSVC 下此代码返回垃圾数字。
我尝试通过将调用约定显式定义为
__cdecl
来调整这个最小的示例,但这都没有帮助。我也尝试使用不同的优化标志来编译它,但它没有改变任何东西;
请注意,我在这里看到了很多类似的问题,但没有一个回答我与 MSVC 相关的问题。
我已经检查了
printf
函数如何转发这些参数,但不幸的是它确实使用 _vfprintf_s_l
将其传递给 va_list
但这就是我在我的情况下不能所做的。
_Check_return_opt_
_CRT_STDIO_INLINE int __CRTDECL _printf_s_l(
_In_z_ _Printf_format_string_params_(0) char const* const _Format,
_In_opt_ _locale_t const _Locale,
...)
#if defined _NO_CRT_STDIO_INLINE
;
#else
{
int _Result;
va_list _ArgList;
__crt_va_start(_ArgList, _Locale);
_Result = _vfprintf_s_l(stdout, _Format, _Locale, _ArgList);
__crt_va_end(_ArgList);
return _Result;
}
#endif
你的代码是一个很大的未定义行为
这里有更正后的版本:
#include <stdarg.h>
int funcA(int a, void* b, ...)
{
va_list args;
va_start(args, b);
auto value = a + va_arg(args, int);
va_end(args);
return value;
}
int funcB(int a, void* b, ...)
{
va_list args;
va_start(args, b);
auto value = funcA(a, args);
va_end(args);
return value;
}
int main() {
return funcB(2, nullptr, 163);
}