2013-03-22 98 views
3

最近我遇到了一個函數的問題,它接受可變數量的參數,並期望最後一個參數爲空指針。 我無法訪問其實施。爲什麼要投射可變參數函數參數?

鑄造是最後一個參數一個void*工作,但傳遞NULLnullptr不適用)直接將不會:

foo(x,y,(void*)NULL); //okay 
foo(x,y,NULL);   //crash 

IMO這不應該有所作爲,但話又說回來,我以前是錯的。你能想到演員會有所作爲的任何理由嗎?或者這只是一個意外事件(一些異步或錯誤的構建或沿着這些線路)

對不起,我不能提供更多的細節。

+3

因爲'NULL'是一個整數,'(void *)NULL'是一個指針嗎?可變參數不會像普通函數那樣轉換任何東西。 – Pubby 2013-03-22 14:55:49

+0

@Pubby我只是不明白這是如何重要的功能。你能提供一個例子嗎? – 2013-03-22 14:56:12

+0

我認爲這是問題,請使用nullptr代替它,它應該工作 – Felics 2013-03-22 14:56:33

回答

12

那麼,NULL是一個在C++中的積分常數,而(void *)NULL是非常明確的指針類型。

因此,當插入到var-arg列表中時,它們可能會有不同的大小。所以這肯定會有所作爲,例如,如果還有其他參數。如果沒有,你最終可能會從var-arg函數中讀取一半的垃圾。

+0

當然,大小不同。我錯過了。很快會接受。 – 2013-03-22 14:58:14

1

NULL是一個空指針常數,所以必須是「整數類型的積分常量表達式prvalue計算結果爲零或std::nullptr_t類型的prvalue。」如果nullptr不可用,我們可以假定它是一個零值整數常數prvalue例如0。失敗指示可變參數調用語義對於void *參數和NULL(促進)類型的參數是不同的,例如,如果指針是64位,並且int是32位。

2

當您使用可變數量的參數(可變參數函數)時,堆棧的構建方式遵循基於類型的構建堆棧的規則。但是,被調用的函數當然不知道堆棧中究竟是什麼。它只需做出假設並繼續。這就是爲什麼將錯誤的參數傳遞給printf是如此危險 - 如果你已經告訴它期望long int,並且只給它一個int,它將從堆棧讀取更多數據,事情會發生。

對於您的問題,整數在您的體系結構中可能不是指針大小。 (也就是說,sizeof(int)!= sizeof(void *))。由於NULL被作爲一個整數壓入堆棧,如果它不是指針大小的話,那麼當函數從堆棧中拉出一個「指針」時,它會抓住誰知道什麼。

整數可能在寄存器中結束,而指針最終在堆棧上,或者可能是一個不同的寄存器文件。我從來沒有在可變參數函數中看到過這種情況,但我懷疑至少有一些編譯器能夠做到這一點。在這種情況下,被調用的函數正在尋找數據的錯誤位置,再次,沒有什麼好處。

相關問題