1 C语言数据类型
1:C语言数据类型
2 C语言数据类型表示范围
(1) 不同数据类型占用的内存大小
C标准所规定的各数据类型所定义变量会占用的内存大小:
在不同的平台上C的每一种数据类型变量所占用的内存大小可能会不同。一般在32位系统之上,char变量占用一个字节内存,short变量占用2个字节内存,int变量占用4个字节内存,float变量占用4个字节内存,double变量占用8个字节内存,long变量占用4个字节内存。每个字节为8位。测试这些数据类型变量占用内存大小时可用sizeof测试一下。
(2) 占用n位的有符号变量表示的范围数为什么是-2^[n - 1] ~ 2^[n - 1] – 1
针对有符号类型变量。
如char 类型变量占用8个位,可表示的数据范围-2^7 ~ 2^7 – 1。为什么呢?
- 在计算机中,数值的一律用[0,1]来表示。
- [0, 1]指数值的补码。
- 正数的补码跟原码(二进制)一致。负数补码为其绝对值的原码按位取反后再加1。
- 补码相加对符号位有进位时,进位被舍弃。
- 变量所占内存的最高位为符号位。最高位为1表示数值为负数,为0表示为数值为正数。
[1]n位所存正数的最大值
如当前数据类型变量占用n位,则在此n位中存最小的正数的补码应该为:
0 | 1 | ...... | 1 | 1 |
符号位 数据最高位 1bit 0bit
则n位所存的最大正数数为:2^0 + 2^1 + …+2^(n-2) = 1*( 1 – 2^[n-1]) / (1 – 2) = 2^[n-1] – 1。
[2]n位所存负数最小值
即补码转换成原码所对应的最大值是- (2^[n-1] – 1)。可根据实际的编程经验可知,最小的负数可以达到-2^[n-1]。
以下依据解决这个问题:
- 反码的出现解决了原码减法计算的不正确性。
- 补码的出现解决了反码计算出现-0的结果,即0用补码表示只有一种形式。
- -0的补码用来表示最小的负数值即-2^[n-1]。
(3) 无符号数据类型变量范围
无符号数就是没有符号,全为正数。所占n位内存的每一位都用来表示数值,则此无符号数的数值范围为:0 ~ 2^n - 1。
(4) 数据溢出
[1]无符号数溢出
如unsigned char ch变量能表示的最大数值为2^8 – 1= 255,最小数值是0,那么当给ch赋255以上值或赋0以下值时ch对应的值是多少呢。
255的补码形式是8个位之上全是1,当255加1成256时,最高位有进位,数据溢出。8位全变为0,ch此时的输出值为0。如此,257对应的ch输出值为1,……,256 + 255 = 511时ch值为255。n * 2^8 ~ (n + 1) 2^8赋值与ch时,ch的有效值为0 ~ 255。[n = 0, 1, 2…,不宜过大]。其中8可以为,16,32,64。
可用程序代表性的验证一下:
- int main(void)
- {
- unsigned char c1, c2, c3, c4;
- c1 = 256;
- c2 = 257;
- c3 = 511;
- c4 = 256 * 10;
- printf("%d, %d, %d, %d\n", c1, c2, c3, c4);
- return 0;
- }
编译并运行程序的结果如下:
misskissc@DeskTop:~/C/Fundation$ gcc datatype.c datatype.c: In function ‘main’: datatype.c:8: warning: large integer implicitly truncated to unsigned type datatype.c:9: warning: large integer implicitly truncated to unsigned type datatype.c:10: warning: large integer implicitly truncated to unsigned type datatype.c:11: warning: large integer implicitly truncated to unsigned type misskissc@DeskTop:~/C/Fundation$ ./a.out 0, 1, 255, 0 |
[2]有符号数溢出
与无符号变量不同的是,最高位已经变成符号位。
如char ch变量的数值范围为[-128,127],当给ch赋-128以下的值或赋127以上的值时ch对应的实际值是多少呢。
上限溢出
[1] 128为正数,将128以补码的形式存为:10000000。
[2] 对于char类型变量来说,这个二进制是char类型变量的补码。这个数值就是补码-0的替身-128。
[3]129存于内存的代码为:10000001。
[4] 对于char类型变量来说,这个二进制是char类型变量的补码。对应的原码为1111 1111,即ch的值为-127。
[5]……
[6]反过来推,当补码为11111111时,对应的原码为1000 0001即ch的值为-1,此时对应的实际的数为127 + 128 = 255。
[7]当255再增1到256时,256对应补码为0000 0000,ch对应的值再次为0。
[8]0 ~ 127是ch的有效值。
当给ch赋值为n * 2^(8-1) ~ (n +1) * 2^(8-1) – 1值时, ch对应的值为-127 ~ -1。[n= 1, 3, 5, 7,…不宜过大]。给ch赋值你n * 2^(8-1)时ch为0。其中指数值8可以为,16,32,64。
当给ch赋值为n * 2^(8-1) ~ (n +1) * 2^(8-1) – 1值时,ch对应值为 0 ~ 127,[n= 2, 4, 6,8…不宜过大]。给ch赋值你n * 2^(8-1)时ch为0。其中指数值8可以为,16,32,64。
程序代表验证:
- int main(void)
- {
- char c1, c2, c3, c4, c5, c6;
- c1 = 128;
- c2 = 129;
- c3 = 255;
- c4 = 128 * 10;
- c5 = 128 * 3 + 1;
- c6 = 128 * 4 + 1;
- printf("%d, %d, %d, %d, %d, %d\n", c1, c2, c3, c4, c5, c6);
- return 0;
- }
编译并执行程序的结果:
misskissc@DeskTop:~/C/Fundation$ gcc datatype.c datatype.c: In function ‘main’: datatype.c:11: warning: overflow in implicit constant conversion datatype.c:12: warning: overflow in implicit constant conversion datatype.c:13: warning: overflow in implicit constant conversion misskissc@DeskTop:~/C/Fundation$ ./a.out -128, -127, -1, 0, -127, 1 misskissc@DeskTop:~/C/Fundation$ |
下限溢出
[1] -129为负数,存于内存中的补码形式为:01111111
得-129补码过程:存有符号数129需要9位,增添一位符号位表示129原码:0 1000 0001,-129的补码为129原码取反加1,即为1 0111 1111,由于char类型变量只有故舍弃最高位得-129在char类型变量中的补码为:0111 1111。
[2] 0111 1111补码表示值为正,即为127。
[3]推测ch输出值为1时的溢出值为 – 129 –(127-1) = -255。
[4]当给ch赋值-256时,ch的输出值为0。
[5]-128 ~ 0是ch的有效值。
当给ch赋值为 - ( (n +1)* 2^(8-1) – 1 ) ~ - n * 2^(8-1)值时,[ n=1, 3, 5, 7,…,不宜过大],ch输出有效值为127 ~ 1。赋n * 2^8时ch的输出值为0。其中指数值8可以为,16,32,64。
当给ch赋值- ( (n + 1)* 2^(8-1) – 1 ) ~ - n * 2^(8-1)时,ch对应的值为-128 ~ -1,[ n=0, 2, 4, 6…,不宜过大]。其中指数值8可以为,16,32,64。
程序代表验证:
- int main(void)
- {
- char c1, c2, c3, c4, c5;
- c1 = -129;
- c2 = -255;
- c3 = -256;
- c4 = -128 * 3- 1;
- c5 = -128 * 4 - 1;
- printf("%d, %d, %d, %d, %d\n", c1, c2, c3, c4, c5);
- return 0;
- }
程序编译及执行结果为:
misskissc@DeskTop:~/C/Fundation$ gcc datatype.c datatype.c: In function ‘main’: datatype.c:8: warning: overflow in implicit constant conversion datatype.c:9: warning: overflow in implicit constant conversion datatype.c:10: warning: overflow in implicit constant conversion datatype.c:11: warning: overflow in implicit constant conversion datatype.c:12: warning: overflow in implicit constant conversion misskissc@DeskTop:~/C/Fundation$ ./a.out 127, 1, 0, 127, -1 misskissc@DeskTop:~/C/Fundation$ |
3总结
(1)判断变量值溢出时的实际输出值步骤
[1]将溢出值以补码的形式存于内存中。
[2]根据数据的类型舍多余位[高位]得到此数据类型下的补码值。
[3]将补码转为原码计算输出值。
(2)溢出规律
[1]无符号数的溢出规律是重复型的:始终都是无符号数的数据范围内。无符号数的下限溢出分析都是一样的。
[2]有符号的溢出规律是交叉型的:上限溢出到下限值,再溢出后回到有效范围内,如此重复。下限溢出后到上限值,再溢出后回到有效范围内,如此重复。
[3]分析溢出还是靠“判断变量值溢出时的实际输出值步骤”来分析。