关于代码示例分析的反馈(安全编码)

时间:2011-03-02 15:21:05

标签: c loops types integer-overflow

我有一段我不确定的作业代码。我有信心我知道答案,但我只是想与社区仔细检查,因为我忘记了一些事情。标题基本上是安全编码,问题只是解释结果。

int main() {
   unsigned int i = 1;
   unsigned int c = 1;
   while (i > 0) {
     i = i*2;
     c++;
   }
   printf("%d\n", c);
   return 0;
}

我的理由是:

乍一看,您可以想象代码将永远运行,考虑到它已初始化为正值且不断增加。这当然是错误的,因为最终这个值会变得如此之大,会导致整数溢出。这反过来也不完全正确,因为最终它会强制变量'i'通过将最后一位设为1来进行签名,因此被视为负数,因此终止循环。因此,它不会写入未分配的内存,因此会导致整数溢出,而是会违反数据类型,从而导致循环终止。

我很确定这是原因,但我只想仔细检查。有什么意见吗?

7 个答案:

答案 0 :(得分:5)

不,unsigned int永远不会作为有符号数与零进行比较。循环结束的唯一机会是变量恰好为零。

后者肯定会发生一次,因为你在每次迭代中乘以2(偶数),这会导致从右边(最不重要的位)插入一个零位,所以经过一定次数的迭代后所有非零位将被“移出数字”,它将变为零。

答案 1 :(得分:2)

处理无符号值时没有溢出。所有计算都以模(UINT_MAX + 1)为模式完成。

所以,会发生的事情是,通过重复乘以2,你最终环绕到零......并且你的循环停止

为简单起见,假设无符号是4位宽。

1 * 2 = 2 ==> 0b0010
2 * 2 = 4 ==> 0b0100
4 * 2 = 8 ==> 0b1000
8 * 2 = 0 ==> 0b0000

答案 2 :(得分:1)

无符号值不会溢出;事实上,它们是保证和定义为环绕的。

答案 3 :(得分:1)

如果是signed integer,则最左边的位设置符号,因此此类型元素可以具有的值范围为 -2147483648至2147483647 。要从正值获得负值,您将对所有位进行反转,反之亦然。

如果是unsigned integer,最左边的位用于存储额外的值。因此,此类型元素可以具有的值范围 0到4294967295

以二进制形式,当i=1;而你只做i = i*2;时,您可以将值作为值:

1 // 1 in base 10
10 // 2 in base 10
100 // 4 in base 10
1000
10000
100000
1000000
10000000
100000000
1000000000
10000000000
100000000000
1000000000000
10000000000000
100000000000000
1000000000000000
10000000000000000
100000000000000000
1000000000000000000
10000000000000000000
100000000000000000000
1000000000000000000000
10000000000000000000000
100000000000000000000000
1000000000000000000000000
10000000000000000000000000
100000000000000000000000000
1000000000000000000000000000
10000000000000000000000000000
100000000000000000000000000000
1000000000000000000000000000000 // 1073741824 in base 10
10000000000000000000000000000000 // 2147483648 in base 10 

现在,如果你有一个循环:while (i > 0) {i如前所述,那么它将处于一个无限循环中,因为它永远不会是0.溢出会发生,但是你的不会制动程序 - 它仍然会运行。

如果变量i已签名(默认),那么您将获得输出c=32,因为整数10000000000000000000000000000000的计算结果为-2147483648,即< 0。但在这种情况下,您不知道输出。

因为这是学校作业,所以教师自然会挑选出一个问题,你无法通过运行提供的代码得出任何结论。我假设,这是因为,您希望了解底层类型的存储方式以及有符号和无符号类型之间的区别。

另外,Java没有无符号原语或不可变数字类。在某些情况下,没有它们会很痛苦。它显然是一个有用的关键字。

答案 4 :(得分:0)

我整个都没有签名。在某些时候它会溢出(或者如果它使它更清晰则环绕)并且变为正好0,它不会是负面的。

答案 5 :(得分:0)

你对溢出是正确的,但是无符号int是无符号的,因为没有符号位因此无符号,无符号整数从0开始,因此它会溢出到0,如果它是无符号的,它会溢出到负数(例如,在32位机器上为-2 ** 31)

答案 6 :(得分:0)

由于i是无符号整数(0 - 255),由于二进制舍入,i在8次迭代后将等于0。