有关C语言中有符号/无符号数混合运算的小问题
生活随笔
收集整理的這篇文章主要介紹了
有关C语言中有符号/无符号数混合运算的小问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
這兩天的工作需要涉及到對無符合數,有符號數作混合運算。
作了一些實驗,發現自己寫了這么多年的程序,以前對于符號數計算相關的理解居然仍存在一些盲點。
有符號數與無符號數混合運算可能有三種混合方式
1。操作數全為有符號數
如:
int a = -1;
int b = 2;
a + b;
2。操作數全為無符號數
如:
unsigned int a = (unsigned int)-1;
unsigned int b = 2;
a + b;
3。操作數混合了有符號數,無符號數
如:
int a = -1;
unsigned int b = 2;
a / b;
情形1和2就不用說了,因為運算中涉及的都是相同符號特征的操作數,計算過程中不會引起歧義。
而對于情形3,由于 涉及到了符號特性相異的操作數,情況就有些復雜了。
這里先說一下, 對于有些運算操作,是要區分有符號與無符號的情況的。比如有符號的除法與無符號
的除法,有符號的取模運算與無符號的取模運算,其計算語意是不同的,具體來說,有符號的除法在x86
平臺上對應的匯編指令是 idiv,而無符號的除法對應的則是 div。
而 對于另外一些操作運算,則是不區分有符號與無符號的,比如,加法,減法,乘法運算。
對于不同操作符與符號相關的情形可以通過下面的小程序來驗證:
int main()
{
signed int n1 = 1;
signed int n2 = 2;
unsigned int u1 = 1;
unsigned int u2 = 2;
signed int a = n1 + n2;
unsigned int ua = u1 + u2;
signed int s = n1 - n2;
unsigned int us = u1 - u2;
signed int m = n1 * n2;
unsigned int um = u1 * u2;
signed int d = n1 / n2;
unsigned int d = u1 / u2;
signed int m = n1 % n2;
unsigned int um = u1 % u2;
return 0;
}
對這一段程序調用 g++ -S,生成相應的匯編文件,就會發現:
加法運算,無論是有符號還是無符號,對應的都是addl指令,
減法 運算 ,對應的都是subl指令,
乘法 運算 ,對應的都是imul指令,
有符號除法 運算 對應的是idiv指令,無符號除法對應的則是 div指令,
有符號數取模運算會用到idiv指令,無符號取模用的則是div指令。
所以回到初始的問題,情形1和2的行為是容易預期的,因為所有操作數都具有同樣的符號特性,直接就
可以得出采用相應符號特性的運算類型。
對于情形3, 因為涉及到不同符號數的混合計算,在計算之前需要先對操作數進行規整化的動
作,規整的原則就是如果操作數中存在至少一個無符號數,則所有操作數都被轉化為無符號數,
運算操作也采用相應的無符號操作符進行,計算完的結果也是一個無符號數。
舉例來說:
(unsigned int)a / (signed int)b 會采用無符號除法進行,其實質相當于
(unsigned int)a / (unsigned int)b
計算結果也是一個無符號數。
再進一步,對于運算 -2 / -1,如果采用有符號數運算, 結果是1,采用無符號數運算, 結果則是0。
所以 (signed int)(-2) / (unsigned int)(-1)的結果就是0了。
除法,取模這樣的操作符在不同的上下文語境里對應的語義動作也有所不同,而且這種差異還不
同于c++里的操作符重載在語言級別可見,而是要到更底層的匯編語言級別才可見,這多少就有
一些tricky,也容易誘使程序員犯錯了。如果有機會我來設計一門語言,我想自己會盡量避免引
入這種tricky的東西的。
作了一些實驗,發現自己寫了這么多年的程序,以前對于符號數計算相關的理解居然仍存在一些盲點。
有符號數與無符號數混合運算可能有三種混合方式
1。操作數全為有符號數
如:
int a = -1;
int b = 2;
a + b;
2。操作數全為無符號數
如:
unsigned int a = (unsigned int)-1;
unsigned int b = 2;
a + b;
3。操作數混合了有符號數,無符號數
如:
int a = -1;
unsigned int b = 2;
a / b;
情形1和2就不用說了,因為運算中涉及的都是相同符號特征的操作數,計算過程中不會引起歧義。
而對于情形3,由于 涉及到了符號特性相異的操作數,情況就有些復雜了。
這里先說一下, 對于有些運算操作,是要區分有符號與無符號的情況的。比如有符號的除法與無符號
的除法,有符號的取模運算與無符號的取模運算,其計算語意是不同的,具體來說,有符號的除法在x86
平臺上對應的匯編指令是 idiv,而無符號的除法對應的則是 div。
而 對于另外一些操作運算,則是不區分有符號與無符號的,比如,加法,減法,乘法運算。
對于不同操作符與符號相關的情形可以通過下面的小程序來驗證:
int main()
{
signed int n1 = 1;
signed int n2 = 2;
unsigned int u1 = 1;
unsigned int u2 = 2;
signed int a = n1 + n2;
unsigned int ua = u1 + u2;
signed int s = n1 - n2;
unsigned int us = u1 - u2;
signed int m = n1 * n2;
unsigned int um = u1 * u2;
signed int d = n1 / n2;
unsigned int d = u1 / u2;
signed int m = n1 % n2;
unsigned int um = u1 % u2;
return 0;
}
對這一段程序調用 g++ -S,生成相應的匯編文件,就會發現:
加法運算,無論是有符號還是無符號,對應的都是addl指令,
減法 運算 ,對應的都是subl指令,
乘法 運算 ,對應的都是imul指令,
有符號除法 運算 對應的是idiv指令,無符號除法對應的則是 div指令,
有符號數取模運算會用到idiv指令,無符號取模用的則是div指令。
所以回到初始的問題,情形1和2的行為是容易預期的,因為所有操作數都具有同樣的符號特性,直接就
可以得出采用相應符號特性的運算類型。
對于情形3, 因為涉及到不同符號數的混合計算,在計算之前需要先對操作數進行規整化的動
作,規整的原則就是如果操作數中存在至少一個無符號數,則所有操作數都被轉化為無符號數,
運算操作也采用相應的無符號操作符進行,計算完的結果也是一個無符號數。
舉例來說:
(unsigned int)a / (signed int)b 會采用無符號除法進行,其實質相當于
(unsigned int)a / (unsigned int)b
計算結果也是一個無符號數。
再進一步,對于運算 -2 / -1,如果采用有符號數運算, 結果是1,采用無符號數運算, 結果則是0。
所以 (signed int)(-2) / (unsigned int)(-1)的結果就是0了。
除法,取模這樣的操作符在不同的上下文語境里對應的語義動作也有所不同,而且這種差異還不
同于c++里的操作符重載在語言級別可見,而是要到更底層的匯編語言級別才可見,這多少就有
一些tricky,也容易誘使程序員犯錯了。如果有機會我來設計一門語言,我想自己會盡量避免引
入這種tricky的東西的。
總結
以上是生活随笔為你收集整理的有关C语言中有符号/无符号数混合运算的小问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 硕鼠怎么用(硕鼠flv视频下载器官方下载
- 下一篇: C变量默认值