C语言数值存储溢出探讨

C语言数值存储溢出探讨

真数与码

真数可以等同于我们数学上的整数,包括正整数,0和负整数。

码是什么呢?

码就是为了存储真数而产生的。

计算机的存储空间不是无穷无尽的,如果未来能实现用一个无穷的二进制位来存储一个数,那么码就没有存在的必要了。

码给各个二进制位设定了一套规则,以达到使用这些二进制位来表示真数的目的。常用的有原码,反码,补码。

现在我们计算机中所使用的的大多是补码,下面的内容也根据补码展开。

如果在提及码的时候没有说明是用多少位来存储的,那么就是在耍流氓

补码

最高位表示符号位,剩余的位表示实际的数据。

这里我假设读者已经熟练掌握真数与补码的转化。

如果没熟练的可以看我写的这篇文章更快的进行进制转换

这里再简单补充一下,补码取最高位为符号位,那么在使用打表法进行快速转换时,最高位的表的值取一个负值即可。例如8位的表取这样的一个序列,-128 64 32 16 8 4 2 1

下面着重介绍当给定的位数无法存储过大或过小的真数(溢出)时,其存储区的变化。

假设我们在用一个8位的存储空间来存储一个数。

其正数最大能存储127,负数最小能存储-128

如果我给出一个真数137,需要存储到这个8位的空间中。

如果我给出一个真数-158,需要存储到这个8位的空间中。

显然,这会产生溢出,那么溢出后,这个存储空间内将会是什么样的内容呢?

1583500500541

为了解决这两个问题(正溢出和负溢出),我们需要熟悉上图的结构。

左边的是其实际的二进制存储空间的内容

中间的一个循环的线性表,不断重复着从127到-128,再到127,再到-128,再到127,再到-128。。。

右边的是我们的真数

未发生溢出时,真数与我们常规的补码转换一致,但是当真数超过所能存储的范围时,就会陷入到这样一个循环中。

知道了这样一个对应关系之后,我们就可以通过取模运算+数数的方式来计算出发生溢出时,存储空间的实际内容。

所以,经过短暂的计算后可得出

真数137其对应的补码是-119即1000 1001

真数-158其对应的补码是98即0110 0010

下面附上代码验证。

int main()
{
	int8_t a = 137;
	int8_t b = -158;

	printf("a: %0x\n", a);
	printf("b: %0x\n", b);


	return 0;
}

执行结果

a: ffffff89
b: 62

0x89: 1000 1001

0x62: 0110 0010

上面所讲到的只是8位的情况,对于32位,64位也遵循同样的规律。

虽然计算机内部使用的是位运算,计算机并不知道真数这样的概念,甚至计算机内部使用的可能是完全的另一套机制,但是上面的这种计算模型总是能够得到正确的结果。如果世上有一种无限接近现实的简单的模型,那么为什么不用呢?

posted @ 2020-03-06 21:51  virgil_devil  阅读(639)  评论(0编辑  收藏  举报