C数据类型变量范围 变量存储 数据溢出

以(unsigned)char为例笔记。数据的溢出实际上是补码运算最高位接受进位或产生进位造成的,可见笔记:C 位运算符操作的二进制码(补码)。

 

1 C语言数据类型

C数据类型变量范围 变量存储 数据溢出_第1张图片

 

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,那么当给ch255以上值或赋0以下值时ch对应的值是多少呢。

 

255的补码形式是8个位之上全是1,当2551256时,最高位有进位,数据溢出。8位全变为0ch此时的输出值为0。如此,257对应的ch输出值为1……256 + 255 = 511ch值为255n * 2^8 ~ (n + 1) 2^8赋值与ch时,ch的有效值为0 ~ 255[n = 0, 1, 2…,不宜过大]。其中8可以为,163264

 

可用程序代表性的验证一下:

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 0001ch的值为-1,此时对应的实际的数为127 + 128 = 255

[7]255再增1256时,256对应补码为0000 0000ch对应的值再次为0

 

[8]0 ~ 127ch的有效值。

当给ch赋值为n *  2^(8-1)  ~  (n +1) * 2^(8-1) – 1值时, ch对应的值为-127 ~ -1[n= 1, 3, 5, 7,…不宜过大]。给ch赋值你n * 2^(8-1)ch0。其中指数值8可以为,163264

 

当给ch赋值为n *  2^(8-1)  ~  (n +1) *  2^(8-1) – 1值时,ch对应值为 0 ~ 127[n= 2, 4, 6,8…不宜过大]。给ch赋值你n * 2^(8-1)ch0。其中指数值8可以为,163264

 

程序代表验证:

 

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类型变量只有故舍弃最高位得-129char类型变量中的补码为:0111 1111

[2] 0111 1111补码表示值为正,即为127

 

[3]推测ch输出值为1时的溢出值为 – 129 –(127-1) = -255

[4]当给ch赋值-256时,ch的输出值为0

 

[5]-128 ~ 0ch的有效值。

当给ch赋值为 - ( (n +1)*  2^(8-1)  – 1 )  ~ - n  *  2^(8-1)值时,[ n=1, 3, 5, 7,…,不宜过大]ch输出有效值为127 ~ 1。赋n * 2^8ch的输出值为0。其中指数值8可以为,163264

 

当给ch赋值- ( (n + 1)*  2^(8-1)  – 1 )  ~ - n  *  2^(8-1)时,ch对应的值为-128 ~ -1[ n=0, 2, 4, 6…,不宜过大]。其中指数值8可以为,163264

 

程序代表验证:

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]分析溢出还是靠“判断变量值溢出时的实际输出值步骤”来分析。

 

C Note Over。

你可能感兴趣的:(c,数据,二进制,C语言,存储)