C語言中 unsigned char 與 signed char 不同輸出格式一些認識
首先考慮下面程式碼輸出什麼?
#include <stdio.h>
int main(void)
{
signed char a = -1;
unsigned char b = -1;
printf("%%d:\n");
printf("%d\n", a);
printf("%d\n", b);
printf("\n%%u:\n");
printf("%u\n", a);
printf("%u\n", b);
return 0;
}
%d格式下 a = -1 b = 255,%u格式下 a = 4294967295 b = 255.
下面我們進行分析為什麼會出現這種結果:
首先數字在記憶體中以他的補碼形式儲存, -1的補碼為全1,這個不會因為他被賦予變數大小或變數型別有無符號而改變。變數大小改變的是儲存此數字的位數,例如signed char 變數 -1補碼儲存在它裡面為 11111111(1位元組。) signed int 為 11111111 11111111 11111111 11111111(假設此時int為4位元組)。變數型別有無符號表示如何看待最高位。 例如 -1 賦予一個 signed char變數 。 則11111111最高位1被當為符號位。 -1被賦予一個unsigned char變數 則11111111 最高位1被當作數值位(不再當作符號位)。
此時我們來分析 signed char -1 以%d 形式輸出。 首先它以補碼形式儲存在此型別變數, 11111111 最高位被當作符號位。 因為要求以%d(十進位制有符號整數型別)輸出。
因此我們將他的補碼補到32位。 因為他為signed 型別,所以補碼補符號位。 11111111前面補24個符號位1即補碼變為FFFFFFFF。 又因為以十進位制有符號整數型別格式輸出(將這個FFFFFFFF看作一個有符號數補碼,將這個補碼以%d格式進行解釋,並輸出),所以把最高位看為符號位,即他為一個負數。 將此負數補碼轉換為原碼可得 10000000 00000000 00000000 00000001所以輸出-1.
同理分析%u 形式輸出。 補完符號位後補碼變為FFFFFFFF。 此時以無符號十進位制整數形式輸出(即把這個FFFFFFFF看做一個無符號數的補碼), 我們將他最高位看做數值位,無符號數即大於等於0數。 所以原碼即補碼 ,所以原始碼為FFFFFFFF的二進位制數值為4294967295.
接下來分析 unsigned char -1. -1以補碼形式儲存在記憶體中的值為全1。 將他賦給一個unsigned char變數時, 為 11111111(依然是這種形式不變)。只是系統認為他的最高位不是符號位,為數值位。 此時以%d 格式輸出,先進行補碼補全。 因為此時為unsigned 所以 11111111前面補數字0而不是符號位. 補全後補碼變為 00000000 00000000 00000000 11111111 此時以%d 格式列印。 最高位為0,系統把他看做一個正數的補碼, 即原碼也是這個。 此原碼值為255.
最後,以%u形式輸出(系統認為此補碼代表一個大於等於0數,所以即使最高位為1,也被當作數值位。而不是把他當作負數)。 00000000 00000000 00000000 11111111 %u格式把最高位當作數值位。 值為255.
此程式碼可判斷你的編譯器char是什麼型別,加上一條 char c = -1; 判斷a.b.c輸出值即可。
下面程式碼是另一種問題:
#include <stdio.h>
int main(void)
{
signed char a = 128;
signed char b = -128;
printf("%%d:\n");
printf("%d\n", a);
printf("%d\n", b);
printf("\n%%u:\n");
printf("%u\n", a);
printf("%u\n", b);
return 0;
}
我們先進行分析,char變數為一個位元組,八位元位。儲存有符號數時最高位為符號位。 而128二進位制形式為10000000.
有符號數128 最高位 為 0 後八位為10000000 儲存在signed char變數中,因為此變數只有八個位元位空間, 所以儲存時被截斷為 10000000.
此時,因為為signed char型別,最高位1被解釋為符號位。
以%d形式輸出,先補全補碼,補符號位1. 11111111 11111111 11111111 10000000. 隨後,%d格式,所以他被解釋為一個負數的補碼,轉化為原碼,數值為-128.
%u格式易得值為.
signed char -128.最高位為1 後八位為100000000。 儲存時被截斷為10000000. 同理可分析,%d%u格式與128輸出相同.