如何在MSVC下正确转发C/C++中的非模板、可变参数

问题描述 投票:0回答:1

我正在尝试在两个函数之间转发非模板变量参数。这些函数都不属于我,所以我无法更改它们的签名。我使用

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
c++ c visual-c++ variadic-templates variadic
1个回答
0
投票

你的代码是一个很大的未定义行为

这里有更正后的版本:

#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);
}
© www.soinside.com 2019 - 2024. All rights reserved.