解釋一下為什么unsigned char在進行取反操作的時候會得出一個和你以為的不同的數字
比如~0xA5結果“應該”是2,但是計算機顯示的卻是250
int main(){ unsigned char a=0xA5,b; b=~a>>5; printf("%u\n",b); }
假定該環境下的寄存器為16位
現在規定unsigned char的值為0xa5,也就是165,將a先取反再向右移5,得出的結果不是2而是250
錯誤思路:
unsigned char占一個字節,即8bit,將a寫入內存中的形式為:
1010 0101
按照常規來說,將a取反為
0101 1010
然后再右移動5個為
0000 0010
結果為2。
但是這里特別要注意一點,低於int類型(即規定的寄存器大小)的基礎類型需要在運算過程中轉化為int類型(寄存器的位數)的大小進行計算,然后在運算完成以后再截取成原大小進行結果的表示,所以這里的過程應該改為:
正確思路:
1010 0101
在16bit的寄存器中轉化為
0000 0000 1010 0101
全部取反得到
1111 1111 0101 1010
而后右向移動5個,左邊補0:
0000 0111 1111 1010
運算完成,開始從右邊截取出unsigned char對應位數的值
1111 1010
該數值為內存中對應數字的補碼形式,但是由於是unsigned型,所以相當於可以直接取用為原碼形式:
即250
這里補充一個取反操作的知識點,我們在學習取反~這個操作
初學者在沒有了解內存是如何存儲數據的情況下往往會發現
取反之后讀取內存中的數字有的時候是需要對內存中的數字取反加一再補負號
而有一些則直接取出當成結果就好,這是為什么呢?
1.一個數字存入內存中的時候,不是直接轉為二進制直接存儲的,編譯器需要把當前數字轉化為其對應的補碼存入內存當中:正數的補碼就是其原碼(即其本身),而負數則需要對其取絕對值再加一。
例1.
-5(char型)轉化為補碼的方式為首先轉為絕對值:
0000 0101 接着取反
1111 1010 再加1
1111 1011 這就是-5在內存中的表現形式
例2.
5的原碼為0000 0101,其補碼也為0000 0101
2.在內存中,若當前數字的補碼最高位為1:表示這個數字為一個負數;需要取出這個數字的時候就需要首先對這個數字進行取反然后加一再補負號還原這個數字。
在內存中,若當前數字的最高位為0:則這個數字表示一個正數,不需要轉化可以直接取出來使用
例1.
需要把-5這個數字從內存中取出
1111 1011 首先取反
0000 0100 然后加一
0000 0101表示5,再補符號
-5 取出成功
例2.
在內存中取出5這個數字:
0000 0101
直接取出的到5即可
3.如何判斷當前數字在取反后從內存取出時應不應該執行取反加一再加符號的操作:根據上面兩條,由於取出數字是在內存當中執行的,所以我們要在取出的時候查看當前數字最高位是否是1,若發現當前數字在完成取反操作以后結果最高位為1是負數,則需要取反加一,反之不需要。
例1.
-5在內存當中表示
1111 1011 進行取反操作得到
0000 0100 編譯器判斷當前數字取反以后變成了正數,在取出這個數字時就不需喲取反加一了
結果就是4
例2.
5在內存中表示為
0000 0101 取反操作
1111 1010 編譯器判斷高位為1是負數,則需要取反加一補符號
0000 0101 先取反然后再加1
0000 0110的到結果6再補符號
~5的結果為-6
====================================================================================