2016-10-13 76 views
2

我似乎無法理解GCC編譯器的警告,當我嘗試將void *值分配給intptr_t變量時,我會得到警告。具體地,當我與-std=c99 -pedantic編譯,我得到關於可變z的第7行的初始化以下警告:是否將void *值設置爲intptr_t變量需要顯式強制轉換?

警告:初始化將指針整數,未作施放[-Wint轉換]

這裏是源代碼:

#include <stdint.h> 

int main(void){ 
     unsigned int x = 42; 
     void *y = &x; 

     intptr_t z = y; /* warning: initialization makes integer from pointer without a cast [-Wint-conversion] */ 

     return 0; 
} 

當然,如果我明確投yintptr_t則警告消失。然而,當intptr_t的整個目的是在void *值的轉換和處理中時,我混淆了爲什麼會出現隱式轉換的警告。

從部分C99標準的7.18.1.4

以下類型表示與屬性有符號整數類型,任何有效 指針空隙可以轉化爲這種類型,那麼轉換回指針空隙, ,其結果將比較等於原始指針:

使用intptr_t

上午我誤解的標準,或者是GCC只是在其「從指針整數」過於迂腐在這種情況下檢查?

+0

這是[上一個問題](http://stackoverflow.com/questions/9492798/using-intptr- t-instead-of-void)有關嗎? –

+3

這不是過於迂腐,隱式轉換隻是警告存在的常見錯誤來源,請考慮在涉及重載解決方案時它會如何變成疼痛。知道你在做什麼,通過做一個(希望是C++風格的)轉換來告訴編譯器 – StoryTeller

+1

intptr_t是一個普通的整數類型,唯一的保證是它可以保存一個void *的所有相關信息,它是對於其他整數類型不能保證,所以警告是正確的。爲什麼你想在第一個地方使用整數?通常一個用於低級算術或位操作RESS。然後強烈建議'uintptr_t'。否則,想想三次(!)如果你真的想要一個整數持有一個指針。 – Olaf

回答

3

總結!對於任何錯誤提前道歉—請給我留言。

在C99:

  • 任何指針可以被轉換爲整數類型。
  • 你可能想這樣做,例如,指針和整數之間if you are implementing your own operating system!
  • 轉換可以去可怕的錯誤,等都是通常不是你想要的。
  • 因此,當您將指針轉換爲整數而不進行轉換時,編譯器會發出警告。這不是過於迂腐,而是爲了避免不確定的行爲。
  • intptr_t(和uintptr_t,以及全文)只是一個整數類型,因此它受到與任何其他指針到整數轉換相同的風險。因此,你會得到同樣的警告。
  • 但是,與intptr_t,你至少知道指針的轉換不會截斷任何位。所以這些是—使用類型明確轉換—如果你真的需要指針的整數值。

    • 該規範1,#6

      ...的 結果是實現定義的。如果結果不能用整數類型表示,則 的行爲未定義。

      隨着intptr_t,結果可以可以在整數類型表示。因此,行爲不是undefined,而只是實現定義的。這就是(據我所知)爲什麼這些類型可以安全地用於從指針接收值。

編輯

參考文獻1,下面,是第6.3節的一部分, 「轉化」。細則中指出:

一些運營商自動轉換操作數值從一種類型到另一個。這 節規定從這樣的隱式轉換所需要的結果......

,指節6.5.4顯式轉換的討論。因此,參考文獻1中的討論確實涵蓋了從任何指針類型到intptr_t的隱式轉換。然後,通過我的閱讀,從void *intptr_t的隱式投射是合法的,並且具有實現定義的結果。 1,4

關於是否明確投應該使用,gcc -pedantic認爲它應該,並且必須有一個很好的理由! :)我個人同意明確演員更清楚。我也認爲代碼應該在沒有任何警告的情況下編譯,如果可能的話,所以如果它是我的代碼,我會添加明確的轉換。

參考

C99 draft(因爲我沒有最終標準的副本),秒。 6.3.2.3#5和#6)。

Id。,秒。 7.18.1.4

Id。,秒。 6.3

ID。,秒。 3.4.1將「實現定義的行爲」定義爲「未指定的行爲,其中每個實現記錄如何進行選擇。「這意味着轉換是合法的,但是在一個平臺上的結果可能與另一個平臺上的結果不同。」

+0

我現在從第6.3.2.3節的第5和第6段中看到,整數和指針之間轉換(因此intptr_t和void *')之間存在固有的風險。如果說從'void *'到'intptr_t'到'void *'的轉換沒有風險*未定義的行爲*(如第6節所述)是否正確,因爲'intptr_t'被定義爲能夠表示結果'void *'轉換? –

+0

只是爲了澄清:隱式轉換對'void *'有效'intptr_t'(雖然有一個實現定義的結果),但通常建議使用顯式類型轉換來使代碼的意圖清晰。那是對的嗎? –

+0

@VilhelmGray編輯 – cxw

相關問題