【问题标题】:x64 va_list in Visual Studio 2005Visual Studio 2005 中的 x64 va_list
【发布时间】:2009-08-13 11:43:45
【问题描述】:

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

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 不应该总是在堆栈上吗?

根据most references,我应该只有一个干净的堆栈,里面装满了传递的参数。

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

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

【问题讨论】:

    标签: visual-studio stack 64-bit win64 variadic-functions


    【解决方案1】:

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

    如果表达式表示 被调用的函数有一个类型 包括一个原型,参数是 隐式转换,好像通过 分配,到的类型 对应的参数,取 每个参数的类型是 其声明的不合格版本 类型。 a中的省略号 函数原型声明器原因 参数类型转换后停止 最后声明的参数。这 默认参数提升是 对尾随参数执行。

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

    如果表达式表示 被调用的函数有一个类型 不包括原型,整数 促销活动在每个 参数和具有类型的参数 浮动被提升为双倍。这些 被称为默认参数 促销。 [...]

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

    【讨论】:

    • 我认为这是正确的。尽管 C++ 标准中没有关于“默认参数提升”的内容,但如果没有,我相信 C 标准适用。据我了解,您引用的文本说,由于传递给变量参数函数的参数没有原型化(因为当它们是变量时您不能对类型进行原型化),它们总是被提升为最大的相关类型 -整数或双精度。我认为奇怪的行为 - 但显然这些是规则。
    【解决方案2】:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-21
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 2011-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多