1. 程式人生 > >C語言中 有符號數、無符號數、整數溢出 (轉)

C語言中 有符號數、無符號數、整數溢出 (轉)

alt 原因 () tar sig 重新 detail copyto 想象

[cpp] view plain copy print?
  1. #include<stdio.h>
  2. void main()
  3. {
  4. int l=-1;
  5. unsigned int c=135;
  6. printf("%u\n",l+c);
  7. }

這個的結果134,而不是我之前認為的很大的正數,實際上需要註意的是-1(0xffffffff)被提升為unsigned int後是一個差1就溢出的unsigned int,所以相加後結果是134。但是如果l=-10000,那麽結果就真是一個很大的正數了,因為不涉及溢出了。
C語言中存在兩種整數算術運算,有符號型和無符號型。無符號數運算:所有無符號數運算都是以2的n次方為模,(n是結果中的位數)。所以它不存在運算時的沒有那種所謂的“溢出”,當它超過範圍時,從零開始重新計數!當一個無符號數和有符號數計算的時候,有符號數會自動轉化為無符號數參與運算!有符號數運算: 是可能發生“溢出”的,而且“溢出”的結果不固定。

關於無符號數減去無符號數的用法錯誤:

if ( i - j >=0) 假如i,j為無符號數,這樣寫可能會引發錯誤,即當i小於j的時候,這個式子仍然成立,因為無符號數始終是大於等於零的。例: if ( strlen( a ) >= 10) 與 if (strlen ( b ) -10 >= 0) 這兩條語句是不相等的 ,因為strlen函數返回的是無符號數類型。

2015年3月8日追加一點:今天看這個地方有些不明白在網上搜了一下資料發現,無符號數相減,如果被減數小於減數,那麽結果會是一個非常大的無符號數,而不是一個想象中的有符號數。所以對於無符號數相減之前需要進行判斷,最好做比較的時候使用 if ( strlen( a ) >= 10) 這種方式,而不要使用if (strlen ( b ) -10 >= 0) 這種方式。因為無符號數進行計算的結果還是無符號數;另外無符號數和有符號數計算時,有符號數會被強制轉提升無符號數。

例如以下這個例子很有意思:

[cpp] view plain copy print?
  1. #include<stdio.h>
  2. int main()
  3. {
  4. unsigned int a=6;
  5. int b=-20;
  6. printf("%d\n",(a+b)>0);
  7. }

這個小例子可以機器試一下。另外還有幾道題不錯我也附在最後。

需要註意一點,我在進行程序編寫的時候發現一個小問題:


那麽unsigned char與signed int相減呢?

[cpp] view plain copy print?
  1. #include<stdio.h>
  2. void main()
  3. {
  4. unsigned char a;
  5. int b;
  6. a=0;
  7. b=2;
  8. printf("X=%d\n",(a-b)>0);
  9. }

ANSI C規定在無符號整數和有符號整數之間進行強制類型轉換時,位模式不應該改變。類型轉換並未改變對象的位模式,改變的是位模式的解釋方式。

有符號數轉換為無符號數時,負數轉換為大的正數(可以理解為原值加上2的n次方),而正數保持不變。

無符號數轉換為有符號數時,對於小的數將保持原值,對於大的數則轉換為負數(可以理解為原值減去2的n次方)。


今晚在看C的時候突然想到如果把大於unsigned int的範圍的數據賦予 該類型變量,printf出來會是什麽樣。

[cpp] view plain copy print?
  1. void main()
  2. {
  3. unsigned int a;
  4. a=7000000000;
  5. printf("a=%d\n",a);
  6. printf("a=%u\n",a):
  7. }

這兩個結果是完全不一樣的。


幾個小例子:

題目一:

int a = -1;

unsigned int b = 1;

printf("%d", a > b);

結果輸出:1

因為無符號數與有符號數比較時,要將有符號數轉化為無符號數,再來比較。a轉化為無符號數後就是0xFFFFFFFF,肯定大於b

題目二:

char a = -1;

unsigned char b = 1;

printf("%d", a > b);

結果輸出:0

奇怪了,怎麽會這樣?這是因為兩者被提升為int了,a提升為int就表示-1,b提升為int 就是1,前者小於後者。註意了這裏不是像題目一裏一樣簡單的把char轉化為unsigned char了

題目三:

int a = -1;

unsigned char b = -1;

printf("%d\n", a < b);

結果輸出是:1

原因在於要把b提升為int就是255當然大於-1了,unsigned char 先提升為int,送入int的低八位中,高位全部補零。

題目四:

char a = -1;

unsigned int b = -1;

printf("%d\n", a == b);

結果輸出:1

原因是char類型被擴展為unsigned int後與b相等,同為0xFFFFFFFF

小於int的提升到int,int之後都是從signed -> unsigned

對於浮點數來說,浮點數(float,double)實際上都是有符號數,unsigned 和signed前綴不能加在float和double之上,當然就不存在有符號數根無符號數之間轉化的問題了。

一定要記住如果需要使用有符號數時不要忘記強制轉換

C語言中 有符號數、無符號數、整數溢出 (轉)