理解有符号和无符号的字符数和整数的转换
网上关于有符号、无符号字符转换成有符号、无符号整形数据的问题,自己写了一个测试程序,分析了下,挺有意思的。
1 测试说明
用的是自己的win7 64位系统,处理器当然是Intel的,因此是前文提到的小端模式
。默认按32位(总线)处理,即一个整型4个字节,长度共 2^32 = 4294967296 字节;有符号字符char类型数据的范围是 -128~127 (对应二进制 11111111~01111111),无符号字符 unsinged char 类型数据范围是 0~255(对应二进制 00000000~11111111)。
2 测试程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
3 三种情形所得结果的分析
3.1 情形1:b = -2
执行b = -2;
后,整型变量b的值 -2 在内存单元中的形式是1111 1111 1111 1111 1111 1111 1111 1110
(共4字节,十六进制0xfffffffe
)。而当执行a = (char *)&b;
后,由于CPU是小端模式
,所以指针变量a指向b的首地址(低地址/低字节1111 1110所在的地址)。由于有符号字符型数据占一个字节(范围-128~127
),所以刚好是变量b的第一个字节1111 1110(十六进制的fe)
。它对应有符号字符型数据-2
,即*a
的值为-2
。然后在打印printf( "*a=[%d]\n", *a );
时,也就是将有符号整型-2以有符号整型数据输出,也就是-2
。
而打印printf( "*a=[%u]\n", *a );
时,是将有符号整型-2以无符号整型数据输出,即求-2的补码形式:已知-2在内存单元中的形式是1111 1111 1111 1111 1111 1111 11111110
(共4字节),由于此时是无符号整数,即最高位1不是符号位,所以值是(2^32 - 1) - 1 = 4294967296 - 2 = 4294967294
。
3.2 情形2:b = 254
执行b = 254;
后,整型变量b的值 254 在内存单元中的形式是0000 0000 0000 0000 0000 0000 1111 1110
(共4字节,十六进制0x000000fe
)。此时指针变量a仍旧指向b的首地址(低地址/低字节1111 1110,即十六进制的fe)。由于有符号字符型数据占一个字节(范围-128~127
),所以刚好是变量b的第一个字节1111 1110(十六进制的fe)
。它对应有符号字符型数据-2
,所以*a
的值为-2
。然后在打印printf( "*a=[%d]\n", *a );
时,也就是将有符号整型-2以有符号整型数据输出,也就是-2
。
同情形1,printf( "*a=[%u]\n", *a );
输出的内容也是4294967294
。
3.3 情形3:b = 129
执行b = 129;
后,整型变量 b 的值 129 在内存中的形式是0000 0000 0000 0000 0000 0000 1000 0001
(共4字节,十六进制0x00000081
)。此时指针变量a仍旧指向b的首地址(低地址/低字节1000 0001所在的地址)。由于有符号字符型数据占一个字节(范围-128~127
),所以刚好是变量b的第一个字节1000 0001(十六进制的81)
。它对应有符号字符型数据-0x7f(即十进制的-127)
,所以*a
的值为-127
。然后在打印printf( "*a=[%d]\n", *a );
时,也就是将有符号整型-127以有符号整型数据输出,也就是-127
。
而打印printf( "*a=[%u]\n", *a );
时,是将有符号整型-127以无符号整型数据输出,即求-127的补码形式:-127的绝对值127的内存单元为0000 0000 0000 0000 0000 0000 0111 1111
(4字节),然后取反得到1111 1111 1111 1111 1111 1111 1000 0000
(共4字节),然后加1得到1111 1111 1111 1111 1111 1111 1000 0001
(共4字节),由于此时是无符号,即最高位1不是符号位,所以共 (2^32 - 1) - (255 - 128 - 1) = 4294967296 -1 - 126 = 4294967169。
Comments »