Summary
0)在进行数据运算、应用变量的时候,肯定要非常分明变量的具体类型
!
1)对于整形数据,数据类型的最高位用于标识数据的符号:最高位为1示意正数
,最高位为0示意整数
。
2)类型溢出时的运算总结:
溢出的值为正
的:理论值为:溢出后的值 - 该类型能示意的个数
溢出的值为负
的:理论值为:溢出后的值 + 该类型能示意的个数
3)十进制正数和补码的互相转换:
如何计算正数的补码:如十进制整数-7,8位
符号位
:1绝对值
:7 <--> 0000 0111取反
:1111 1000加1
:1111 1001(补码)
如何从一个补码推算十进制正数:如已知(1111 1001)示意一个十进制正数
上述规定反向
计算
减1
:1111 1000取反
:0000 01111绝对值
:计算得7符号位
:-7
非凡的
,如1个字节的整数-128
,它没有原码和反码,只有补码为1000 0000,即应用(-0)来示意(-128)。但依然能够应用上述规定进行推算二进制补码。
4)C语言中的变量默认为
有符号的类型signed
;unsigned关键字将变量申明为无符号类型,留神:只有整数类型
才能够申明为unsigned
5)当无符号数和有符号数进行数学运算时,有符号数会被转换为有符号数
,运算后果为无符号数
。
有符号与无符号数分析
1、负数和正数
数据类型的最高位用于标识数据的符号
- 最高位为
1
,标识这个数为正数
最高位为
0
,标识这个书为负数
int sign = 0;char i = -5;short j = 5;int k = -1;sign = (i & 0x80); // i为正数,最高位为1 ==> sign != 0sign = (j & 0x8000); // j为负数,最高位为0 ==> sign == 0sign = (k & 0x80000000);// k为正数,最高位为1 ==> sign != 0
2、原码和补码
2.1 类型溢出的运算
在计算机外部用原码示意无符号数
- 无符号数默认为负数
- 无符号数没有符号位
对于固定长度的无符号数
- MAX_VALUE + 1 --> MIN_VALUE
- MIN_VALUE - 1 --> MAX_VALUE
类型溢出时的运算总结:
溢出的值为正
的:理论值为:溢出后的值 - 该类型能示意的个数
溢出的值为负
的:理论值为:溢出后的值 + 该类型能示意的个数
eg1:char c = 256;
剖析:有符号char的示意范畴为[-128, 127],256超过了能示意的最大值127,因而
理论值为:溢出后的值 - 该类型能示意的个数
,即256 - 28 = 0;char c = 256;printf("c = %d\n", c); // c = 0;
eg2:char c = -200;
剖析:有符号char的示意范畴为[-128, 127],256超过了能示意的最小值-128,因而
理论值为:溢出后的值 + 该类型能示意的个数
,即-200 + 28 = 56;char c = -200;printf("c = %d\n", c); // c = 56;
eg3:unsigned char c = 256;
剖析:无符号char的示意范畴为[0, 255],256超过了能示意的最大值255,因而
理论值为:溢出后的值 - 该类型能示意的个数
,即256- 28 = 0;unsigned char c = 256;printf("c = %d\n", c); // c = 0;
eg2:usigned char c = -200;
剖析:无符号char的示意范畴为[0, 255],-200超过了能示意的最小值0,因而
理论值为:溢出后的值 + 该类型能示意的个数
,即-200 + 28 = 56;char c = -200;printf("c = %d\n", c); // c = 56;
2.2 正数如何用补码示意
在计算机外部用补码
示意正数
- 负数的补码就是负数自身
正数的补码为正数的绝对值各位取反后加1
- 如:8位整数 5 的补码为:0000 0101 (负数的原码、反码、补码都一样)
- 如:8位整数 -7 的补码为:1111 1001
如何计算正数的补码:如十进制整数-7,8位
符号位
:1绝对值
:7 <--> 0000 0111取反
:1111 1000加1
:1111 1001(补码)
如何从一个补码推算十进制正数:如已知(1111 1001)示意一个十进制正数
上述规定反向
计算
减1
:1111 1000取反
:0000 01111绝对值
:计算得7符号位
:-7
3、signed和unsigned关键字
- C语言中的变量
默认为
有符号的类型signed
unsigned关键字将变量申明为无符号类型,留神:
只有整数类型
才能够申明为unsignedint i; // 默认为有符号整形signed int j; // 显示申明变量为带符号整形unsigned int k; // 申明变量为无符号整形
4、问题示例
eg.1 以下代码输入什么?
unsigned int i = 5;int j = -10;if((i+j) > 0){ printf("i + j > 0 \n" );}else{ printf("i + j <= 0 \n");}
理论输入:(i + j > 0
)。依照数学运算-10 + 5 = -5,小于0,应该打印(i + j <= 0)才是,为什么?
解析:当无符号数和有符号数进行数学运算时,有符号数会被转换为有符号数
,运算后果为无符号数
。
- 计算i + j时,将j晋升为unsigned int。
- -10是一个正数,在内存中
以补码模式来存储
,理论内存里的二进制值为0xFFFF FFF6
(算法见上)。把0xFFFF FFF6以一个无符号数来解释,即此时的j是一个超大的数为4,294,967,286。 - 而后加上5即为0xFFFF FFFB,4,294,967,291。所以i + j > 0
eg.2 以下代码输入什么?
unsigned int i = 0;for(i = 9; i>=0; i--){ printf("i = %u\n", i);}
理论输入:死循环。而不是只输入0 - 9。
解析:对于无符号整形i,当运算类型溢出
时,理论值会向反方向的值聚拢。
- 当i = 0时,此时执行i--,冀望i的值为-1。但实际上i的类型是unsigned int,能示意的范畴为[0, 4,294,967,295]。-1不在能示意的范畴内,依照下面
类型溢出
时的算法,此时的理论值为:-1 + 232 = 4,294,967,295,依然大于0。所以会不停的计算。
本文总结自“狄泰软件学院”唐佐林老师《C语言进阶课程》。
如有错漏之处,恳请斧正。