目录
2.2证明补码与原码互相转换,其运算过程(计算逻辑)是相同的
一、整型家族成员
//char(字符的本质时ASCLL码值,是整型)(char 是无符号还是有符号的标准未定,取决与编译器的实现)
//unsigned char
//signed char
//short
//unsigned short [int]
//signed short [int]
//int
//unsigned int
//signed int
//long
//unsigned long [int]
//signed long [int]
//long long
//unsigned long long [int]
//signed long long [int]
二、整型数据长度
printf("%d\n", sizeof(char));//输出:1;
printf("%d\n", sizeof(short));//输出:2;
printf("%d\n", sizeof(int));//输出:4;
printf("%d\n", sizeof(long));//输出:4(x86)/8(x64);
printf("%d\n", sizeof(long long));//输出:8;
三、整形在内存中的存储:原码、反码、补码
1.计算机中整数的三种二进制表示方法
//计算机中的整数有三种二进制表示方法,即原码、反码、补码;
三种表示方法均有符号位和数值位两部分,符号位是指32位二进制数的最高位,用0表示”正“,用1表示”负“。数值位正数的原、反、补码都相同;负整数的原码、反码、补码各不相同。
原码:直接将数值按照正负数的形式翻译成二进制就可以得到原码;
反码:将原码的符号位不变,其他位依次按位取反就可以得到反码;
补码:反码+1就得到补码;
2.整型数据在内存中存放的是补码
//对于整型来说:数据在内存中存放的就是补码;
计算机系统中,数值一律用补码来表示和存储;原因在于使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器);此外,补码与原码互相转换,其运算过程(计算逻辑)是相同的,不需要额外的硬件电路;
2.1证明使用补码的合理性,且加法和减法可以统一处理
//计算对比 1-1=0 和 1+(-1)的结果;
//使用原码,无法求出正确的计算结果;
0000 0000 0000 0000 0000 0000 0000 0001 -- 1的原码
1000 0000 0000 0000 0000 0000 0000 0001 -- -1的原码
(1的原码) + (-1的原码),得
1000 0000 0000 0000 0000 0000 0000 0010 -- 结果为-2,结果错误;
//使用补码,计算结果正确;
0000 0000 0000 0000 0000 0000 0000 0001 -- 1的补码
1111 1111 1111 1111 1111 1111 1111 1111 -- -1的补码
1+(-1) 两个补码相加,得
0000 0000 0000 0000 0000 0000 0000 0000 -- 结果为0,结果正确;
//通过以上代码,1-1等于0,1+(-1)也等于0,两个结果一致,证明使用补码可以统一处理加减法,且计算结果正确,证明了使用补码的合理性;
2.2证明补码与原码互相转换,其运算过程(计算逻辑)是相同的
1000 0000 0000 0000 0000 0000 0000 0001 -- -1的原码
-1的原码取反加一,得到补码
1111 1111 1111 1111 1111 1111 1111 1111 -- -1的补码
方式一:-1的补码减一取反,得到原码
1111 1111 1111 1111 1111 1111 1111 1110 -- -1的反码
1000 0000 0000 0000 0000 0000 0000 0001 -- -1的原码
方式二:-1的补码取反加一,得到原码
1000 0000 0000 0000 0000 0000 0000 0000 -- -1的补码取反
1000 0000 0000 0000 0000 0000 0000 0001 -- -1的补码取反加一,即 -1的原码
//由此可见,将补码 先减一 再取反,可以得到原码;将补码 先取反 再加一,也可以得到原码;
2.3通过题目理解原码、反码、补码及其运算
//练习:求以下代码输出结果;
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("a=%d,b=%d,c=%d", a, b, c);//输出结果为:-1,-1,255;
return 0;
}
//本题解析:
3.整型在内存中的存放的二进制数和取值范围之间的关系
以char类型为例,char类型大小为1个字节,即8个比特位;
//signed char 类型(最高位为0则为正,最高位为1则为负) 存放的补码为:
0000 | 0000 | -- 数字 0 (原码为 0000 0000) |
0000 | 0001 | -- 数字 1 (原码为 0000 0001) |
…… | ||
…… | ||
0111 | 1111 | -- 数字 127 (原码为 0111 1111) |
1000 | 0000 | --该补码直接被定义为数字 -128 |
1000 | 0001 | -- 数字 -127 (原码为 1111 1111) |
…… | ||
…… | ||
1111 | 1110 | -- 数字 -2 (原码为 1000 0010) |
1111 | 1111 | -- 数字 -1 (原码为 1000 0001) |
0000 | 0000 | -- 数字 0 (原码为 0000 0000) |
//由此可见,signed char 类型存放的补码,能代表的数字范围只有 -128~127 ;同时,当8个比特位都为1时(二进制数1111 1111,代表数字-1),再+1,将得到二进制数0000 0000,即再次回到数字0,形成循环;
//unsigned char 类型(最高位无论是0或1都为正) 存放的补码为:
0000 | 0000 | -- 数字 0 (原码为 0000 0000) |
0000 | 0001 | -- 数字 1 (原码为 0000 0001) |
…… | ||
…… | ||
0111 | 1111 | -- 数字 127 (原码为 0111 1111) |
1000 | 0000 | -- 数字 128 (原码为 1000 0000) |
1000 | 0001 | -- 数字 129 (原码为 1000 0001) |
…… | ||
…… | ||
1111 | 1110 | -- 数字 254 (原码为 1111 1110) |
1111 | 1111 | -- 数字 255 (原码为 1111 1111) |
0000 | 0000 | -- 数字 0 (原码为 0000 0000) |
//由此可见,signed char 类型存放的补码,能代表的数字范围只有 0~255 ;同时,当8个比特位都为1时(二进制数1111 1111,代表数字255),再+1,将得到二进制数0000 0000,即再次回到数字0,形成循环;
以上以char类型为例,其他整型家族类型的二进制存储和取值范围,可依此类推;
四、整型类型的取值范围
//整型家族的取值范围定义在头文件 <limits.h> 中;
//整型家族的取值范围:
printf("%d~%d\n", CHAR_MIN, CHAR_MAX);//char的取值范围:-128~127
printf("%d~%d\n", SCHAR_MIN, SCHAR_MAX);//signed char的取值范围:-128~127
printf("%u\n", UCHAR_MAX);//unsigned char的取值范围:0~255
printf("%d~%d\n", SHRT_MIN, SHRT_MAX);//shor 的取值范围:-32768~32767
printf("%d\n", USHRT_MAX);//unsigned shor 的取值范围:0~65535
printf("%d~%d\n", INT_MIN, INT_MAX);//int 的取值范围:-2147483648~2147483647
printf("%u\n", UINT_MAX);//unsigned int 的取值范围:0~4294967295
printf("%ld~%ld\n", LONG_MIN, LONG_MAX);//long(x86) 的取值范围:-2147483648~2147483647
printf("%lu\n", ULONG_MAX);//unsigned long(x86) 的取值范围:0~4294967295
printf("%lld~%lld\n", LLONG_MIN, LLONG_MAX);//long 的取值范围:-9223372036854775808~9223372036854775807
printf("%llu\n", ULLONG_MAX);//unsigned long 的取值范围:0~18446744073709551615
( --end-- )