2011-05-03 59 views
12

我通常可以理解編譯器警告背後的原因,但這個看起來只是錯誤的。由編譯器警告困惑,建議int8_t的複合賦值提升爲int

#include <stdint.h>  
uint8_t myfunc(uint8_t x,uint8_t y) 
{ 
    x |= y; 
    return x; 
} 

英特爾編譯器與-Wall抱怨:

conversion from "int" to "uint8_t={unsigned char}" may lose significant bits 
    x |= y; 
    ^

這是正確的?上述代碼是不可移植的還是非標準的?

+0

總結在接受答案的評論:編譯器在技術上是正確的,有是int到uint8_t的轉換,但聲稱可能會丟失重要位,這是令人失望的錯誤。 – 2011-05-06 12:21:42

回答

9

這是integer promotions工作。

x |= y; 

|操作的兩個操作數都提升到int

x = (int)x | (int)y; 

然後將結果轉換回uint8_t失去精度。

+4

警告說「可能會丟失重要的位」。這是公然錯誤的。該操作不會丟失位。 – 2011-05-03 14:55:06

+0

編譯器當然可以自由地優化代碼,並以8位完成所有操作。它仍然會發出警告。 – 2011-05-03 14:55:35

+0

@R,從'int'或'unsigned int'到'uint8_t'的轉換可能會丟失位。認識到沒有顯着的損失會給編譯器編寫者帶來太多麻煩,而且收益甚微。 – 2011-05-03 14:58:31

5

它是正確的。運營商向int推薦參數。見this page更多細節,第一句話開始:

沒有算術用C在精度比int短則做[...]

4

對於計算,xy的值被提升爲int,但警告仍然是假的。 |運算符不能將結果的位寬增加到操作數的寬度之外,這些操作數已在uint8_t之中,因爲它們是從uint8_t升級的。絕大多數這種警告選項標誌都是完全有效且正確的代碼,除非您想在這樣的100個問題上浪費時間,否則我認爲最好關閉或忽略這些警告。

+0

不要關閉警告,有些情況下您錯誤地沒有準備好隱式促銷。假設你沒有簽名被提升爲無意中籤署了一個循環,你會想知道這一點。 – AJG85 2011-05-03 15:20:50

+0

@ AJG85:但問題是*你會知道嗎?* - 當警告被掩埋時,這個選項會產生數百個其他假冒警告。這就是爲什麼編譯器編寫者修復警告是非常重要的,以便它們只在實際可能出錯的情況下觸發。如果他們用虛假警告淹沒你,你會(1)忽略它們,或者(2)關閉選項。我認爲選項(2)稍好一些,因爲它可以避免隱藏其他類型的警告*,這種警告可能具有較高的信噪比,在大量僞造的警告中。 – 2011-05-03 15:34:55

+0

我會提出這個問題_is與編譯器爭鬥值得保存幾個字節的內存嗎?_你可能只能回答是,而不是知道警告是否是真實的以及如何處理它。我沒有警告,但在執行'signed int'操作時也不使用'unsigned char'。 – AJG85 2011-05-03 15:49:27

1

編譯器警告可能看起來毫無意義,因爲操作不可能產生超過8位,但它只是一個更大的操作類別的子集。例如,如果用+=代替|=,則溢出的可能性變得非常真實。

消除警告的方式是告訴你有意識地扔掉了投位編譯器:

x = (uint8_t)(x | y); 
+0

除了你不會丟掉...... – 2011-05-03 15:31:48

+0

@R,你確定,只是你已經知道它們都是零。也許我應該改爲「有意識地忽略高位」。 – 2011-05-03 15:37:11