3 回答

TA貢獻1829條經(jīng)驗 獲得超13個贊
在無符號類型中生成負數(shù)的減法結(jié)果是明確定義的:
[...]涉及無符號操作數(shù)的計算永遠不會溢出,因為無法由結(jié)果無符號整數(shù)類型表示的結(jié)果以比模式結(jié)果類型可以表示的最大值大1的數(shù)量減少。(ISO / IEC 9899:1999(E)§6.2.5/ 9)
如您所見,(unsigned)0 - (unsigned)1
等于-1模UINT_MAX + 1,或換句話說,UINT_MAX。
請注意,雖然它確實說“涉及無符號操作數(shù)的計算永遠不會溢出”,這可能導致您認為它僅適用于超出上限,但這被表示為句子的實際綁定部分的動機:“a無法用結(jié)果無符號整數(shù)類型表示的結(jié)果以模數(shù)減少為模數(shù),該數(shù)字大于可由結(jié)果類型表示的最大值。該短語不限于類型上限的溢出,并且同樣適用于太低而無法表示的值。

TA貢獻1835條經(jīng)驗 獲得超7個贊
使用無符號類型時,會發(fā)生模運算(也稱為“環(huán)繞”行為)。要理解這種模塊化算法,只需看看這些時鐘:
9 + 4 = 1(13 mod 12),所以對另一個方向是:1 - 4 = 9(-3 mod 12)。使用無符號類型時應(yīng)用相同的原則。如果結(jié)果類型是unsigned,則進行模運算。
現(xiàn)在看一下將結(jié)果存儲為以下操作unsigned int:
unsigned int five = 5, seven = 7;
unsigned int a = five - seven; // a = (-2 % 2^32) = 4294967294
int one = 1, six = 6;
unsigned int b = one - six; // b = (-5 % 2^32) = 4294967291
當您想確保結(jié)果是signed,然后將其存儲到signed變量或轉(zhuǎn)換為signed。如果想要獲得數(shù)字之間的差異并確保不應(yīng)用模運算,那么您應(yīng)該考慮使用以下abs()定義的函數(shù)stdlib.h:
int c = five - seven; // c = -2
int d = abs(five - seven); // d = 2
要非常小心,特別是在寫條件時,因為:
if (abs(five - seven) < seven) // = if (2 < 7)
// ...
if (five - seven < -1) // = if (-2 < -1)
// ...
if (one - six < 1) // = if (-5 < 1)
// ...
if ((int)(five - seven) < 1) // = if (-2 < 1)
// ...
但
if (five - seven < 1) // = if ((unsigned int)-2 < 1) = if (4294967294 < 1)
// ...
if (one - six < five) // = if ((unsigned int)-5 < 5) = if (4294967291 < 5)
// ...

TA貢獻1797條經(jīng)驗 獲得超4個贊
那么,第一種解釋是正確的。但是,你在這種情況下對“簽名語義”的推理是錯誤的。
再次,你的第一個解釋是正確的。無符號算術(shù)遵循模運算的規(guī)則,這意味著對32位無符號類型0x0000 - 0x0001
求值0xFFFF
。
但是,第二種解釋(基于“簽名語義”的解釋)也需要產(chǎn)生相同的結(jié)果。即使您0 - 1
在簽名類型的域中進行評估并獲得-1
作為中間結(jié)果,-1
仍然需要0xFFFF
在以后將其轉(zhuǎn)換為無符號類型時生成。即使某些平臺對有符號整數(shù)使用奇異表示(1的補碼,有符號幅度),在將有符號整數(shù)值轉(zhuǎn)換為無符號整數(shù)值時,仍需要使用該平臺來應(yīng)用模運算規(guī)則。
例如,這個評估
signed int a = 0, b = 1;unsigned int c = a - b;
仍保證生產(chǎn)UINT_MAX
中c
,即使該平臺采用異國情調(diào)的代表符號整數(shù)。
- 3 回答
- 0 關(guān)注
- 1026 瀏覽
添加回答
舉報