2

我有一个类非静态成员函数,它有可变参数,我在 64 位 Windows 上使用 64 位运行时在 Visual Studio 2005 上编译。

void Class::Foo(void* ptr,...)
{
    va_list args;
    va_start(args,ptr);
    float f=va_arg(args,float);
    va_end(args)
}

我期待一个浮点数,我将一个浮点数传递给函数。但是当我调试时 - 我没有得到我通过的浮点数。事实上 - 它被函数作为 64 位双精度接收!我必须这样做:

double d=va_arg(args,double);
float f=(float)d;

现在我知道 Win64 喜欢在寄存器中传递参数,并在这样做时转换浮点数,va_list 不应该总是在堆栈上吗?

根据大多数参考资料,我应该只有一个干净的堆栈,里面装满了传递的参数。

我的问题是:这是正确的行为,还是错误?如果它是一个错误,是我的错误,还是微软的?

我有定义 WIN64 和 _M_AMD64,而 WIN32 是未定义的。

4

2 回答 2

1

我这里没有 C++ 标准,但在这件事上它遵循 C 标准。C99,6.5.2.2p7 说

如果表示被调用函数的表达式具有包含原型的类型,则参数被隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型作为其声明的非限定版本类型。函数原型声明器中的省略号会导致参数类型转换在最后一个声明的参数之后停止。默认参数提升是在尾随参数上执行的。

因此,对于您的 float 参数,将执行“默认参数提升”。这些在 p6 中定义为

如果表示被调用函数的表达式的类型不包含原型,则对每个参数执行整数提升,而浮点类型的参数将提升为双精度。这些称为默认参数提升。[...]

因此,所有浮点数在传递给椭圆时都会转换为双精度。VS 在这方面显然符合,并且错误在您的代码中,不应该floatva_arg.

于 2009-08-13T12:55:32.117 回答
1

看起来这是一个 VC++ x64 错误。

修复: va_arg 函数在 Visual C++ 2005 应用程序中返回不正确的值

于 2009-08-14T20:55:31.723 回答