2012年12月24日 星期一

Unsigned vs. Signed

Unsigned vs. Signed


2013/07/02
新增幾個受益良多的連結
http://novus.pixnet.net/blog/post/26896236-back-to-basic%3A-%E8%AB%87unsigned
http://kezeodsnx.pixnet.net/blog/post/32341565-unsigned-vs-signed


在定義整數變數的型態的時候可以加上 unsigned 或是 signed, 例如
unsigned char
unsigned short (int)
unsigned long (int)
unsigned int
----------
signed char
signed short (int)
signed long (int)
signed int
--------------
上面 signed 有加和沒有加是一樣的意義




加上 unsigned 以後,

1. 所需要的資料儲存空間和沒有加 unsigned 時是一樣的

2. 在使用 printf() 列印時基本上你必須分清楚
unsigned 有影響到的是參數的傳遞, 使用 %d 或是
%u 基本上是看程式設計者自己的選擇

int i=-1;
printf("%d %u\n", i, i);

會印出
-1 4294967295

unsigned int i=-1;
printf("%d %u\n", i, i);

也會印出
-1 4294967295

char i=-1;
printf("%d %u\n", i, i);

還是會印出
-1 4294967295

但是
unsigned char i=-1;
printf("%d %u\n", i, i);
則會印出
255 255
這不是 %d 和 %u 的問題, 而是
參數傳遞時資料轉換的問題 (見下面第 3 項)


不一樣的地方有下面幾個

1. 資料的範圍基本上加上 unsigned 以後會變成 2 倍

2. 程式裡比較大小的時候

int i=1;
int j=-1;
if (i>j) printf("i>j\n");
else printf("i<=j\n");
你會發現結果是 i>j

unsigned int i=1;
int j=-1;
if (i>j) printf("i>j\n");
else printf("i<=j\n");
你會發現結果是 i<=j

也就是說 signed 和 unsigned 在比較的時候 compiler
會把 signed int 自動當成 unsigned int 來比較

2. 資料轉換的時候 (或是函式呼叫的時候)
char i = -128;
int j = i;
變數 i 裡面的資料只有 1 個位元組, 要放進
變數 j 裡面的時候需要做 sign extension
也就是多出來的 3 個位元組 (24 個 bit) 都要
填入原來 i 的 sign bit (第 8 個 bit)
以上例來說 (用二進位表示)
i: 10000000
j: 11111111 11111111 11111111 10000000

unsigned char i = -128;
int j = i;
由 unsigned 轉為 signed 時前面一率補 0
用二進位表示
i: 10000000
j: 00000000 00000000 00000000 10000000

char i = -128;
unsigned int j = i;
還是做 sign extension
用二進位表示
i: 10000000
j: 11111111 11111111 11111111 10000000

函式呼叫的時候會做型態的轉變, 例如
void fun(int x)
{
...
}

呼叫時如果用
unsigned char i=-1;
fun(i);
就會自動做轉換

呼叫 printf 時會做 default promotion
因為 printf 函式的定義如下
int printf(const char *format, ...)

其中的 ... 代表可以接受任意型態和個數
的參數, 所有小於四個位元組的整數資料一律
轉換為四個位元組, 浮點數一律轉為八個位元組

所以在轉換時也會根據傳入參數是否有 unsigned
來做 sign extension


4. 可能還有其它不同點我現在一下子想不起來


Source:  http://squall.cs.ntou.edu.tw/cprog/Materials/Unsigned.html