TypeCodes

理解有符号和无符号的字符数和整数的转换

网上关于有符号、无符号字符转换成有符号、无符号整形数据的问题,自己写了一个测试程序,分析了下,挺有意思的。

1 测试说明

用的是自己的win7 64位系统,处理器当然是Intel的,因此是前文提到的小端模式。默认按32位(总线)处理,即一个整型4个字节,长度共 2^32 = 4294967296 字节;有符号字符char类型数据的范围是 -128~127 (对应二进制 11111111~01111111),无符号字符 unsinged char 类型数据范围是 0~255(对应二进制 00000000~11111111)。

C语言有符号和无符号数

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
/**
 * @FileName :  signedandunsigned.c
 * @Author   :  vfhky 2014.10.21 https://typecodes.com/cseries/signedunsignedcharconvint.html
 * @Function :  对有符号和无符号数的测试
 */
#include <stdio.h>

int main( int argc, char * argv[] )
{
    char * a = NULL;
    int b;

    //情形1,b的值在有符号字符型数据范围内
    b = -2;
    a = (char *)&b;
    printf( "*a=[%d]\n", *a );      //输出 *a=[-2]
    printf( "*a=[%u]\n\n", *a );    //输出 *a=[4294967294]

    //情形2,b的值不在无符号字符型数据范围内
    b = 254;
    printf( "*a=[%d]\n", *a );      //输出 *a=[-2]
    printf( "*a=[%u]\n\n", *a );    //输出 *a=[4294967294]

    //情形3,b的值在无符号字符型数据范围内
    b = 129;
    printf( "*a=[%d]\n", *a );      //输出 *a=[-127]
    printf( "*a=[%u]\n", *a );      //输出 *a=[4294967169]

    return 0;
}

对有符号signed和无符号unsigned数的测试

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 »