2011-05-24 68 views
2

的可能損失,我有以下的C代碼:條件運算符:從 'INT' 爲'無符號字符的轉換,數據

a = (b == B1) ? A1 : A2; 

abA1A2B1都是unsigned char類型。 A1,A2B1都是常數。

VC時正在編制++我看到下面的警告:

warning C4244: '=' : conversion from 'int ' to 'unsigned char ', possible loss of data 

我不明白這樣的警告 - 沒有一個變量是int類型。據推測,某種隱含的轉換正在發生,但爲什麼?

奇怪的是,下面的代碼(這是功能相同)編譯沒有警告:

if (b == B1) { 
    a = A1; 
} else { 
    a = A2; 
} 

到目前爲止我所知,兩個代碼提取物應該是相同的。

+0

使用'#define A1 42','A1'的類型是'int',而不是'unsigned char'。只是說。無論如何......我傾向於認爲你是用C++編譯器編譯的,而且問題是錯誤標記的。 – pmg 2011-05-24 18:11:40

+0

@pmg - 常量被定義爲casts - 請參閱下面我對Paulo的回答的評論。我不知道在編譯C而不是C++代碼時MS VC++是否做了什麼不同,所以我不知道這是否有所作爲。 – sam 2011-05-24 18:32:50

+0

那麼,你的編譯器試圖比它真正需要的更有幫助:)關於將'int'分配給'unsigned char'的警告不需要C. – pmg 2011-05-24 19:10:24

回答

4

在三元?:操作者的C語言算術參數經受通常的算術轉換,即,它們都提升到int執行任何進一步的計算之前。它們是否是常量並不重要。重要的是,他們有unsigned char(正如你所說)和unsigned char?:總是首先被提升。基本上,C語言從不執行任何類型小於int的計算。首先將小一些的東西轉換成int

這也是你的情況。基本上,你的

a = (b == B1) ? A1 : A2; 

由C語言解釋爲

a = ((int) b == (int) B1) ? (int) A1 : (int) A2; 

,這就是爲什麼你會得到警告。同樣,A1A2是常數的事實不起作用。

a = A1; 

右手邊不經受積分的推廣,這就是爲什麼這裏沒有警告。此外,即使A1被明確聲明爲int常量,在這個微不足道的情況下(直接分配),如果大多數編譯器能夠看到該常量在目標類型unsigned char的範圍內,它們不會發出警告。 ?:的情況比較複雜,因此編譯器可能會恢復到通用行爲併發出警告。

+0

謝謝 - 我現在已經找到了詳細描述這種行爲的C99標準的相關部分。 6.5.15,p5:「如果第二個和第三個操作數都具有算術類型,那麼將由常規算術轉換確定的結果類型應用於這兩個操作數,結果的類型就是這種類型。」 – sam 2011-05-24 19:14:48

2
a = (unsigned char)((b == B1) ? A1 : A2); 

我相信這是因爲在子語句中沒有rvalues - 它們會在詞法分析器中自動轉換爲int。上面的代碼應該解決警告消息,並且不會影響生成的代碼。

3

儘管功能相同,但兩個代碼並不完全相同。

您會發現,當您使用三元運算符,即condition ? true_value : false_value時,編譯器會嘗試在這些值之間推斷出最佳可能類型。

因爲A1和A2是常量(就像你在O.P.中說明的那樣),編譯器用它們的實際值替換它們的位置,完全忽略數據類型,將它們都作爲整數呈現。

因此,有必要把結果,因爲這樣的:

a = (unsigned char)((b == B1) ? A1 : A2); 
+0

這很有道理。稍微有點奇怪/令人煩惱,因爲常量是通過一個強制類型明確地定義的(例如'#define A1((unsigned char)0x01)) - 但我猜測編譯器仍然可以自由地查看這些值,正如你所建議的那樣。 – sam 2011-05-24 18:15:22

+0

那麼,這個答案是不正確的。首先,OP明確指出常量具有'unsigned char'類型,即它們是通過強制轉換來聲明的。編譯器不會忽略該類型,而是將操作數提升爲更大的類型。 – AnT 2011-05-24 18:37:12

相關問題