代码示例分析反馈(安全编码)
我有一段来自我不确定的作业的代码。我确信我知道答案,但我只是想与社区再次确认,以防我忘记了某些内容。标题基本上是安全编码,问题只是为了解释结果。
int main() {
unsigned int i = 1;
unsigned int c = 1;
while (i > 0) {
i = i*2;
c++;
}
printf("%d\n", c);
return 0;
}
我的推理是这样的:
乍一看,您可以想象代码会永远运行,因为它被初始化为正值并且不断增加。这当然是错误的,因为最终该值会变得很大,从而导致整数溢出。这反过来也不完全正确,因为最终它将通过将最后一位设置为 1 来强制对变量“i”进行签名,因此被视为负数,从而终止循环。因此,它不是写入未分配的内存并因此导致整数溢出,而是违反了数据类型并因此导致循环终止。
我很确定这就是原因,但我只是想仔细检查一下。有什么意见吗?
I have a piece of code from an assignment I am uncertain about. I feel confident that I know the answer, but I just want to double-check with the community incase there's something I forgot. The title is basically secure coding and the question is just to explain the results.
int main() {
unsigned int i = 1;
unsigned int c = 1;
while (i > 0) {
i = i*2;
c++;
}
printf("%d\n", c);
return 0;
}
My reasoning is this:
At first glance you could imagine the code would run forever, considering it's initialized to a positive value and ever increasing. This of course is wrong because eventually the value will grow so large it will cause an integer overflow. This in turn is not entirely true either, because eventally it will force the variable 'i' to be signed by making the last bit to 1 and therefore regarded as a negative number, therefore terminating the loop. So it is not writing to unallocated memory and therefore cause integer overflow, but rather violating the data type and therefore causing the loop to terminate.
I am quite sure this is the reason, but I just want to double check. Any opinions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
不,
unsigned int
永远不会与作为有符号数的零进行比较。循环结束的唯一机会是变量恰好为零。后者肯定会发生一次,因为在每次迭代中乘以 2(偶数),这会导致从右侧插入一个零位(最无意义的位),因此经过一定次数的迭代后,所有非零位都将是“移出数字”,它将变为零。
No,
unsigned int
will never compare against zero as a signed number. The only chance for the loop to end is for the variable to become exactly zero.The latter will surely happen once since you multiply by 2 (an even number) in each iteration and this causes a zero bit to be inserted from right (least meaningful bit), so after some number of iterations all non-zero bits will be "shifted out of the number" and it will become zero.
处理无符号值时不会发生溢出。所有计算均以
(UINT_MAX + 1) 为模。
因此,所发生的情况是,通过重复乘以 2,该值最终会回绕到零......并且循环停止
假设,为了简单起见,无符号数是 4 位宽。
There is no overflow when dealing with unsigned values. All calculations are done modulo
(UINT_MAX + 1)
.So, what happens is that the value by repeatedly multiplying by 2 you eventually wrap-around to zero ... and your loop stops
Suppose, for simplicity sake, that unsigned is 4 bits wide.
无符号值不会溢出;事实上,它们被保证并定义为环绕。
unsigned values do not overflow; they are, in fact, guaranteed and defined to wrap-around.
对于
有符号整数
,最左边的位设置符号,因此该类型元素可以具有的值范围为-2147483648到2147483647。要从正值得到负值,您需要对所有位进行位反转,反之亦然。对于
无符号整数
,最左边的位用于存储额外的值。因此,此类型元素可以具有的值范围是 0 到 4294967295。以二进制形式,当
i=1;
并且您只执行i = i*2;
时,您可以拥有的值是:现在,如果您有一个循环如下:
while (i > 0) {
和i
的作用如前所述,那么它将处于无限循环中,因为它永远不会是 0。溢出将发生,但你不会阻止程序 - 它仍然会运行。如果变量
i
有符号(默认),那么您将得到输出c=32
作为整数 10000000000000000000000000000000 计算结果为 -2147483648 ,即< 0 。然而在这种情况下您不知道输出。
既然是功课,那么老师自然会挑出一个问题,你无法通过运行提供的代码得出任何结论。我认为,这是因为,您希望您了解底层类型的存储方式以及有符号类型和无符号类型之间的区别。
另外一个事实是,Java 没有无符号基元或不可变数字类。在某些情况下,没有它们可能会很痛苦。这无疑是一个有用的关键字。
In case of
signed integer
, the left most bit sets the sign, so the range of values that this type element can have are -2147483648 to 2147483647. To get negative value from positive value you do bit inverse to all bits and vice-versa.In case of
unsigned integer
, the left most bit is use to store extra values. So i range of values that this type element can have are 0 to 4294967295.In binary form, when
i=1;
and you only doi = i*2;
then values, that you can have as values are:Now, if you have a loop like:
while (i > 0) {
andi
acts as described before, then it will be in a infinite loop, as it will never be 0. Overflows will occur, but thy will not brake program - it will still be running.In case variable
i
is signed (default), then you would get outputc=32
as integer 10000000000000000000000000000000 evaluates to -2147483648 and that is< 0
. In this case however you do not know the output.As it is schoolwork, then naturally teachers have picked a problem, where you can not conclude anything from running the code provided. I assume, that this is because, thy want you to know how underlaying types are stored and what is difference between signed and unsigned types.
Just as an extra fact, Java does not have unsigned primitives or immutable number classes. Not having them can be painful, in some cases. It is diffidently a useful keyword.
你对溢出的看法是正确的,但是无符号整型由于某种原因而无符号(没有符号位,因此无符号,无符号整型从0开始),因此它会溢出到0,如果它是无符号的,它会溢出到负数数字(例如,在 32 位计算机上为 2**31)
you are right about the overflow, but an unsigned int is unsigned for a reason (there is no sign bit hence unsigned, an unsigned int starts at 0) therefore it will overflow to 0, if it was unsigned it would have overflown to a negative number (- 2**31 on a 32 bit machine for example)
由于 i 是无符号整数 (0 - 255),因此由于二进制舍入,经过 8 次迭代后 i 将等于 0。
As i is an unsigned integer (0 - 255), i will equal 0 after 8 iterations due to binary round off.
i 始终未签名。在某些时候它会溢出(或者如果这样更清楚的话会环绕)并恰好变成 0,它永远不会是负数。
i is unsigned throughout. At some point it will overflow (or wrap around if that makes it clearer) and become exactly 0, it cannot ever be negative.