原文:https://blog.csdn.net/guotianqing/article/details/77341657
背景
最近在項目中遇到了一個編譯警告,是因為定義的變量為char[],而在使用時作為函數的unsigned char*類型的參數調用。這個警告很容易避免,但是char*和unsigned char*到底有什么區別呢,本文作一個簡單的探討。
char 和 unsigned char 的區別
在C中,默認的基礎數據類型均為signed,如定義變量為int,long等,都為有符號的。如果要定義無符號類型,必須顯式地在變量類型前加unsigned。
char vs unsigned char
相同點:在內存中都是一個字節,8位(2^8=256),都能表示256個數字
不同點:char的最高位為符號位,因此char能表示的數據范圍是-128~127,unsigned char沒有符號位,因此能表示的數據范圍是0~255
實際使用中,如普通的賦值,讀寫文件和網絡字節流都沒有區別,不管最高位是什么,最終的讀取結果都一樣,在屏幕上面的顯示可能不一樣。
但是要把一個char類型的變量賦值給int、long等數據類型或進行類似的強制類型轉換時時,系統會進行類型擴展,這時區別就大了。對於char類型的變量,系統會認為最高位為符號位,然后對最高位進行擴展,即符號擴展。若最高位為1,則擴展到int時高位都以1填充。對於unsigned char類型的變量,系統會直接進行無符號擴展,即0擴展。擴展的高位都以0填充。所以在進行類似的操作時,如果char和unsigned char最高位都是0,則結果是一樣的,若char最高位為1,則結果會大相徑庭。
可以使用的下面的小程序驗證一下:
#include <stdio.h> static void func(unsigned char uc) { char c; int i, j; unsigned int ui, uj; c = uc; i = (int)c; j = (int)uc; ui = (unsigned int)c; uj =(unsigned int)uc; printf("%%c: %c, %c\n", c, uc); printf("%%x: %x, %x\n", c, uc); printf("%%u: %u, %u\n", ui, uj); printf("%%d: %d, %d\n", i, j); } int main(int argc, char *argv[]) { func(0x80); func(0x7f); return 0; }
運行結果如下:
%c: �, �
%x: ffffff80, 80
%u: 4294967168, 128
%d: -128, 128
---------------------------
%c:,
%x: 7f, 7f
%u: 127, 127
%d: 127, 127
對於char來說,0x80用二進制表示為1000 0000,當它作為char賦值給unsigned int或 int 時,系統認為最高位是符號位,會對最高位進行擴展。而0x7F用二進制表示為0111 1111,最高位為0,不會擴展。對於unsigned char來說,不管最高位是0,還是1,都不會做擴展。
char* 和 unsigned char*的區別
char* 和 unsigned char* 也具有類似的區別,如下面測試程序所示:
char*是有符號的,如果大於127即0x7F的數就是負數了,使用%x格式化輸出,系統自動進行了符號擴展,就會產生變化。
所以在涉及到類型提升的上下文中,要注意使用char*和unsinged char*的區別。
#include <stdio.h> int main(int argc, char *argv[]) { unsigned char k = 0; int i = -1; short a = -12345; char *p; unsigned char *q; printf("sizeof(i) = %d\n",sizeof(i)); printf("sizeof(a) = %d\n",sizeof(a)); printf("-----------------------------\n"); printf("begin p(char):\n"); p = (char*)&a; printf("a = %u | %d\n",a,a); for(k=0;k<sizeof(a);k++) { printf("0x%x ",*(p++)); } printf("\n"); p = (char*)&i; printf("i = %u | %d\n",i,i); for(k=0;k<sizeof(i);k++) { printf("0x%x ",*(p++)); } printf("\n"); printf("-1 > 0u: %s\n",(-1>0u ? "true":"false")); printf("-----------------------------\n"); printf("begin q(unsigned char):\n"); q = (unsigned char*)&a; printf("a = %u | %d\n",a,a); for(k=0;k<sizeof(a);k++) { printf("0x%x ",*(q++)); } printf("\n"); q = (unsigned char*)&i; printf("i = %u | %d\n",i,i); for(k=0;k<sizeof(i);k++) { printf("0x%x ",*(q++)); } printf("\n"); printf("-1 > 0u: %s\n",(-1>0u ? "true":"false")); return 0; }