2009-08-13 63 views
2

我有一個類非靜態成員函數,它具有可變參數,我正在使用64位運行時在64位Windows上編譯Visual Studio 2005。x64在Visual Studio 2005中的va_list

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是未定義的。

回答

1

這裏我沒有C++標準,但它在這個問題上遵循C標準。 C99,6.5.2.2p7說

如果表示 調用的函數的表達有一個類型,它包括 一個原型,參數 隱式轉換,彷彿 分配的類型的 對應的參數,取 類型的每個參數爲 其聲明的 類型的不合格版本。 函數原型聲明符中的省略號表示導致 參數類型轉換在 上次聲明的參數後停止。 默認參數促銷是 對結尾參數執行。

因此,對於你的float參數,執行「默認參數促銷」。 這些在P6定義爲

如果表示 調用的函數的表達式有一個類型,做 不包括一個原型, 優惠在每個 參數執行的整數,和參數具有類型 浮動提升一倍。這些 被稱爲默認參數 促銷。 [...]

因此,所有浮點數在傳遞給橢圓時都會轉換爲double類型。 VS顯然符合這方面的要求,而且錯誤出現在你的代碼中,它不應該在va_arg中使用float

+0

我認爲這是正確的。雖然C++標準中沒有關於「默認參數促銷」的內容,但是我認爲C標準不適用。據我所知,你引用的文字說,因爲傳遞給變量參數函數的參數不是原型的(因爲你不能在變量類型時對它們進行原型設計),它們總是被提升爲最大的相關類型 - int或double。奇怪的行爲我認爲 - 但顯然這些是規則。 – Roderick 2009-08-19 19:58:46