1 unsigned int i=3; 2 cout<<i * -1;問結果是多少。
第一反應:-3。不過結果似乎不是這樣的,寫了個程序,運行了一下,發現是:4294967293。
1)在32位機上,int型和unsigned int型都是32位的(4個字節)。 2)enum會跟據最大值來決定類型,一般來說為int型,如果超出int型所能表示的范圍,則用比int型大的最小類型來表示(unsigned int, long 或者unsigned long) 3)關於類型的大小。一般用所能表示的數據范圍來比較類型的大小,如char型<unsigned char型<short型...在表達式中,一般都是由小的類型向大的類型轉換(強制類型轉換除外) 下面結合自己查的資料,加上自己不斷地舉各種情況編程,總結一下關於類型轉換(僅限於算術表達式中關於整數類型的轉換)的一些問題(如有缺漏,歡迎補充,感激不盡) 1、所有比int型小的數據類型(包括char,signed char,unsigned char,short,signed short,unsigned short)轉換為int型。如果轉換後的數據會超出int型所能表示的范圍的話,則轉換為unsigned int型; 2、bool型轉化為int型時,false轉化為0,true轉換為1;反過來所有的整數類型轉化為bool時,0轉化為false,其它非零值都轉為true; 3、如果表達式中混有unsigned short和int型時,如果int型數據可以表示所有的unsigned short型的話,則將unsigned short類型的數據轉換為int型,否則,unsigned short類型及int型都轉換為unsigned int類型。舉個例子,在32位機上,int是32位,范圍–2,147,483,648 to 2,147,483,647,unsigned short是16位,范圍0 to 65,535,這樣int型的足夠表示unsigned short類型的數據,因此在混有這兩者的運算中,unsigned short類型數據被轉換為int型; 4、unsigned int 與long類型的轉換規律同3,在32位機上,unsigned int是32位,范圍0 to 4,294,967,295,long是32位,范圍–2,147,483,648 to 2,147,483,647,可見long類型不夠表示所有的unsigned int型,因此在混有unsigned int及long的表達式中,兩者都被轉換為unsigned long; 5、如果表達式中既有int 又有unsigned int,則所有的int數據都被轉化為unsigned int類型。 經過這番總結,前面提出的問題的答案應該就很明顯了吧。在表達式i*-1中,i是unsigned int型,-1是int型(常量整數的類型同enum),按第5條可以知道-1必須轉換為unsigned int型,即0xffffffff,十進制的4294967295,然後再與i相乘,即4294967295*3,如果不考慮溢出的話,結果是12884901885,十六進制0x2FFFFFFFD,由於unsigned int只能表示32位,因此結果是0xfffffffd,即4294967293。 在C語言中,signed要求最高位是符號位,以下表示數據大小,而unsigned則全部位都表示大小。如果用8位二進制表示的話,signed范圍就是-128到127,unsigned就是0到255,C語言中專門用兩個關鍵字來描述兩種表示方法,於是,就產生了一些不可思議的問題。
1、溢出
在有符號運算中可能會產生溢出問題,歸納起來就是:兩個整數相加可能會溢出,兩個負數相加也可能會溢出,一正一負相加肯定不會溢出。在《C深度剖析》中看到一個有趣的問題。
1 #include <stdio.h> 2 #include <string.h> 3 int main(void) 4 { 5 char a[1000]; 6 int k = 0; 7 for (; k < 1000; k++) 8 { 9 a[i] = -1-i; 10 11 } 12 printf("%d\n", strlen(a)); 13 return 0; 14 }
最終的結果是255。因為數組a[1000]是char類型的,在C語言中明確規定char類型占一個字節內存空間,且在x86的gcc平台上 char默認是signed,一開始,k=0,a[0]=-1,隨著k不斷增大,當k=127,則a[127]=-128,對應的二進制是 10000000,我們知道-128是編譯器能表示的最小值,當k=128,a[128]當然不可能存儲-129這個值了,因為最高位發生了溢出,所以在 計算機中儲存的補碼值是01111111,。隨著k繼續增大,當k=254時,a[254]在計算機中存放的補碼是00000001,而 k=255,a[255]對應的存儲值是00000000,即0,strlen函數遇到第一個0就停止,所有最後的結果是k從0到254,總共長度是 255。
2、signed和unsigned混合運算
C語言中除了char類型,編譯器默認其他整型都是signed,在x86的gcc平台上包括char在內所有整型都是signed。
1 #include <stdio.h> 2 3 int main(void) 4 { 5 unsigned a = 10; 6 unsigned b = -10; 7 if (a) printf("yes\n"); else printf("no\n"); 8 if (b) printf("yes\n"); else printf("no\n"); 9 10 int c = b; 11 printf("%d\n", c); 12 if (c) printf("yes\n"); else printf("no\n"); 13 14 int d = -20; 15 int e = a + d; 16 printf("%d\n", e); 17 if (e) printf("yes\n"); else printf("no\n"); 18 19 return 0; 20 }
最後結果是
yes
yes
-10
yes
-10
yes
從上面例子可以看出,在C語言中,有符號數可以賦值給無符號數,結果是一個無符號數,而無符號數也可以賦值給有符號數,結果還是一個無符號數;在混合運算中,只要有一個無符號數,都會將有符號數轉化成無符號數參加運算,結果也以無符號保存。
注意:signed 和 unsigned 在電腦中的存儲形式是一樣的,只是解釋方法不同,即一個有符號,一個無符號。
%d打印的是signed類型的,而%u才是打印的unsignd類型的,用不同的打印相當於一個類型轉換了。當然C++比較直觀,能直接自動識別出類型並打印值。
就用上面的例子:
unsigned c = 3; printf("%d\n",(c*(-1))); // 打印出的是-3 printf("%u\n",(c*(-1))); // 打印出的是4294967293