char, 到底是个什么怪物?

int main() {
	
	//0x80是有歧义的,可以表示128,也可以表示-128

	// 正数            0x01 0x02... 0x7E  0x7F  0x80 0x81
	//                 1    2       126   127   128  129
	// 零              0x00
	// 负数(补码表示)  0xFF 0xFE... 0x82  0x81  0x80
	//                 -1   -2      -126  -127  -128
    
    #undef CHAR
	#define CHAR unsigned char 
	CHAR c = 0x80;
	int x = c;  //x == 128

    #undef CHAR
    #define CHAR signed char 
	CHAR d = 0x80;
	int y = d;  //y == -128

	//由上述代码可知,CHAR的符号性(有符号或无符号),决定了对0x80的解释。
	//由于c变量的类型是无符号的char,0x80不可能是负数,只可能是正数128
	//由于d变量的类型是有符号的char,则0x80有两种解释方式,128或-128.
	//C语言认为,负数的收尾位是1代表负数,而0x80的二进制为:0b1000000, 因此选择了-128
	//所以d的值是-128
	//而且,规定了signed char的范围是-128 ~ 127, 超过范围的正数128要做截断处理。截断的结果是-128
	//编译器做出了警告:从0x80到d会截断

	//这个知识有什么用呢?

	char e = 0x80;
	int z = e;  //z的结果是什么?
	//z的结果是依赖于编译器的。主要由以下规则确定
	//1) char 等同于 unsigned char 或者 char等同于signed char 由实现(编译器厂家)决定。
	//   因此这段代码将不会有“可移植性”了。

	//2) char的长度,可能是1个字节,2个字节,也是有实现(编译器厂家)决定的。
	//   在char是2个字节时,不管它是有符号的,还是无符号的,结果都是128

	//因此建议char类型做算数运算,或位运算时,不要依赖于下面的“常规假设”:char是8位的,char是有符号的。
	//例如: 如果“常规假设”是成立的,也适用于大部分编译器,则
	{
		char a = 0x01;
		char b = 0x80;
		int x = a + b;   //a (promote to int) ==> 0x00000001 ; b( promote to int ) 0xFFFFFF80  
		                 //补码的好处就是,正数和负数运算时,可以直接做加法运算。因此 x == 0xFFFFFF81
		int y = a ^ b;   //a (promote to int) ==> 0x00000001 ; b( promote to int ) 0xFFFFFF80  
		                 //做位逻辑运算时,也是按位的运算,只可惜b提升为int后,会出现一大堆FFFFFF,因此y == 0xFFFFFF81
	}
	//例如: 如果“常规假设”是不成立的:char是无符号的,char是8位的
	{
		char a = 0x01;
		char b = 0x80;
		int x = a + b;   //a (promote to int) ==> 0x00000001 ; b( promote to int ) 0x00000080  
						 //x == 0x00000081
		int y = a ^ b;   //a (promote to int) ==> 0x00000001 ; b( promote to int ) 0x00000080  
						 //做位逻辑运算时,也是按位的运算,因此y == 0x00000081
	}

	//例如: 如果“常规假设”是不成立的:char是有符号的,char是16位的
	{
		char a = 0x01;
		char b = 0x80;
		int x = a + b;   //a (promote to int) ==> 0x00000001 ; b( promote to int ) 0x00000080  
						 //x == 0x00000081
		int y = a ^ b;   //a (promote to int) ==> 0x00000001 ; b( promote to int ) 0x00000080  
						 //做位逻辑运算时,也是按位的运算,因此y == 0x00000081
	}
	
	//当char仅仅是当做存储二进制数据的容器使用时,或者当做字符的存储容器时,就比较安全,不用考虑符号性。

	return 0;
}

你可能感兴趣的:(就你不知道)