2011-12-07 44 views
12

我知道,右移負簽名類型取決於實現,但如果我執行左移,該怎麼辦?例如:左和右移負整數定義的行爲?

int i = -1; 
i << 1; 

這是明確的嗎?

我認爲標準的不說,大約有符號整型負值

如果E1已經簽署的類型和非負值,E1×2 E2是 可表示在結果類型那麼這就是結果的價值; 否則,行爲是不確定的。

它只是澄清,如果結果不能用signed型表示,那麼行爲是未定義的。

+8

什麼部分不清楚? *如果* E1具有非負值且... *否則*行爲未定義。 E1具有負值,因此行爲未定義。的確,有時標準可以用一些額外的括號來完全清楚「其他」所指的是什麼,但這裏的意思是「在任何未描述的情況下」。它有助於解釋這些事情時要記住,在標準沒有描述行爲的任何情況下,行爲是不確定的。所以實際上「否則」在形式上是多餘的。 –

+0

@SteveJessop:我認爲__otherwise__表示如果該值不可表示,則行爲未定義。我不確定這是否包括負值的E1。 – user103214

+1

@Norman:確實如此,參見R.Marthinho的回答,有一個分號,在條件和最終結果之間有一個明確的分隔符。 – Xeo

回答

24

你不能正確讀這句話。該標準在以下情況下定義它:左邊的操作數具有帶符號的類型非負值結果可表示(以前在同一段落中將其定義爲無符號類型)。在所有其他情況下(注意該句子中的use of the semicolon),即如果這些條件中的任何一條未被驗證,則行爲是不確定的。

+1

+1以獲得更好的解釋。 – Xeo

+1

+1分號 – Pubby

+0

如果我有一個非負數,並且我右移了太多次,該怎麼辦? 'int i = 1;我>> 24;'這是有效的嗎?只是困惑。 – user103214

3

否則,行爲是未定義的。

這包括

如果E1有符號類型和非負值

11

當C標準被編纂時,不同的平臺在左移負整數時會做不同的事情。其中一些行爲可能會觸發特定於實現的陷阱,這些陷阱的行爲可能不在程序的控制範圍之內,並且可能包含隨機代碼執行。儘管如此,爲這些平臺編寫的程序可能會利用這種行爲(例如,程序可能會指定用戶在運行之前必須先做一些配置系統的陷阱處理程序,但程序可以利用適當配置的陷阱處理程序)。 C標準的作者並不想說負值數據左移的機器的編譯器必須進行修改以防止這種陷阱(因爲程序可能會依賴於它),但是如果遺漏的話,允許移動一個負數可以觸發一個可能導致任意行爲(包括隨機代碼執行)的陷阱,這意味着左移一個負數可以做任何事情。因此未定義的行爲。在實踐中,直到大約5年前,爲使用二補數學(意味着自1990年以來製造的機器的99 +%)的機器編寫的編譯器的99 +%將持續產生以下行爲x<<yx>>y,在這種程度上,代碼依賴於這種行爲被認爲不再是不可移植的,而不是假定char是8位的代碼。 C標準沒有強制要求這樣的行爲,但是任何希望與廣泛的現有代碼兼容的編譯器作者都會遵循它。

  • 如果y是有符號類型,x << yx >> y好像y被摔簽名進行評估。
  • if x is type int,x<<y相當於(int)((unsigned)x << y)
  • if x is type int and positive,x>>y equivalent to (unsigned)x >> y。如果x類型爲int且爲負,則x>>y等同於〜(〜((無符號)x)>> y)。
  • 如果xlong類型,則類似規則適用,但unsigned long而不是unsigned
  • 如果x是N位型和y大於N-1時,則和x >> yx << y可以任意產生零,或者可以作爲雖然右操作數是y % N行動;他們可能需要額外的時間與y成比例[請注意,在32位機器上,如果y是負數,這可能是一個長時間,雖然我只知道一臺機器,實際上它會運行超過256個額外的步驟]。編譯器在選擇時不一定是一致的,但總會返回其中一個指示值而沒有其他副作用。

不幸的是由於某種原因,我不能完全參透,編譯器的編寫者已經決定,而不是允許程序員表示應該使用什麼假設編譯器死代碼去除,編譯器應該假設它是不可能執行的任何變化其行爲不是C標準所要求的。因此,給定代碼如下所示:

uint32_t shiftleft(uint32_t v, uint8_t n) 
{ 
    if (n >= 32) 
    v=0; 
    return v<<n; 
} 

編譯器可確定,因爲代碼將接合未定義的行爲,當n爲32或更大時,編譯器可以假定if絕不會返回true,並且因此可以省略代碼。因此,除非有人提出了C標準才能恢復經典行爲,並允許程序員指定哪些假設值得刪除死代碼,否則不能將此類結構推薦給任何可能饋送到超現代編譯器的代碼。

+1

感謝這個美妙的答案 - 即使它不是公認的,它也非常有用。 –

+0

另一件需要記住的事情是,並非所有桶式換檔器都是相同的。我似乎回想起ARM的行爲與IA32和其他平臺的行爲有點不同,它的原因是沒有隱式的mod操作,只使用移位量的較低位。 – jww

+0

@jww:包含「shift-by-N」指令的平臺通常會減少移位值,但在許多情況下,mod減少的數量大於字的大小。此外,家庭中不同的芯片可能會有不同的表現。然而,幾乎所有的處理器都會使用列出的兩種行爲之一。 – supercat