2017-10-16 61 views
28

C11§6.5.7第5段:是「-1 >> 5;」 C中未指定的行爲?

E1 >> E2結果是E1右移E2比特位置。如果 E1具有無符號類型或者如果E1具有帶符號類型和 非負值,則結果的值是E1/2*^E2的商的整數部分。 如果E1具有簽名類型和負值 值,則結果值是實現定義的。

但是,該viva64參考文件說:

int B; 
B = -1 >> 5; // unspecified behavior 

我跑GCC此代碼,它總是給輸出-1

所以,標準說的是「如果E1有簽署類型和負值,所得到的值是實現定義的」,但該文件說的是-1>>5;不確定的行爲

那麼,在C中是-1>>5;未指定的行爲?哪個是對的?

+17

如果您正在嘗試編寫可移植代碼,那麼實現定義和未指定之間的區別不是很重要,因此代碼檢查器會以類似方式處理它們。 – Barmar

+1

它是實現定義的。 – chux

+0

@chux那麼,那個文件是不正確的? – rsp

回答

33

兩者都是正確的。實現定義的行爲是特定類型的未指定行爲。

引述的the C standard 3.4.1節定義「實現定義的」:

實現定義

未指定的行爲,其中每個執行文件如何選擇由

示例實現定義的行爲的一個示例是t當有符號整數右移時,他傳播高位 。

從第3.4.4節定義 「未指定的行爲」:

未指定的行爲

使用未指定的值,或者其他行爲,其中該 國際標準提供了兩種或更多的可能性,並施加 沒有進一步的要求,在任何情況下選擇

示例未指定行爲的示例是評估函數參數的順序。

至於GCC,你總會得到相同的答案,因爲操作是實現定義的。它實現了通過符號擴展

負數右移從GCC documentation

符號整型的一些位操作的結果(C90 6.3,C99和C11 6.5)。

位運算符作用於包括 兩者的符號和值的位值,其中符號位是最高值值比特以上立即考慮 的表示。 簽字>>通過符號擴展作用於 負數。

作爲一個擴展的C語言,GCC不使用C99和C11給出 緯度唯一治療簽訂<<作爲 未定義的某些方面。但是,-fsanitize=shift(和-fsanitize=undefined)將 診斷此類情況。他們也被診斷,在需要不斷表達 的地方。

+1

這不完全正確:「實現定義的行爲是一種特定類型的未指定行爲」。如果行爲是實現定義的,則標準指定實現必須定義並記錄它,所以它不是未指定的。未指定的行爲適用於實現可以自由選擇但不必記錄行爲或使其一致的情況。 –

+7

@R除「實現定義的行爲」的定義實際上使用確切的詞語「未指定的行爲」。我想要求文件不被認爲是強加於「選擇的進一步要求」。 – aschepler

+1

我會解釋你引用的「實現定義的行爲」的定義,它不包括「未指定的行爲」,即含義爲「對於未指定的行爲,但也對此要求」。畢竟,「未指定的行爲」的定義包括「對所選擇的行爲沒有進一步的要求」,但是實現定義的行爲的確要求實現記錄選擇,因此它不符合「未指定行爲」的定義, –

12

「未指定的行爲」和「實現定義」並不矛盾。這僅僅意味着C標準沒有具體說明需要發生什麼,而且各種實現可以做他們認爲「正確」的事情。

在一個編譯器上多次運行並獲得相同結果僅意味着特定編譯器是一致的。您可能會在不同的編譯器上得到不同的結果。

+1

兩個術語都不是另一個的子集。如果一個動作調用「未指定」行爲,那麼實現需要從一組有限的選擇中進行選擇(例如,'x()+ y()'必須像完全評估x()一樣,然後評估y()或完全y()然後評估x()。那些是唯一的兩個選擇)。如果某個動作調用「實現定義」行爲,則需要實現文檔記錄特定行爲,但只要記錄它們就可以做任何他們喜歡的任何事情。 – supercat

相關問題