请解释以下段落。
“接下来的问题是我们是否可以在不失去精度的情况下为变量赋值。如果我们只是在加法或减法期间检查溢出是不够的,因为有人可能会添加1到-5并分配结果到一个unsigned int。那么实际的加法不会溢出,但结果仍然不合适。“
当我加1到-5时,我没有任何理由担心。答案是应该是-4。 那么结果不合适的问题是什么? 你可以在这里找到我要去的完整文章:
答案 0 :(得分:5)
尝试将其分配给unsigned int,而不是int。
术语unsigned int
是关键 - 默认情况下,int数据类型将包含负数和正数;但是,无符号整数总是为正。它们提供了这个选项,因为从技术上来说,uints可以比常规的有符号整数保持更大的正值,因为它们不需要用一点来跟踪它的负面还是正面。
请参阅:
答案 1 :(得分:5)
在32位字中的-4的二进制表示如下(十六进制表示法)
0xfffffffc
当解释为无符号整数时,此位模式表示数字 2 ** 32-4 或18446744073709551612.我不确定我会称这种现象“溢出”,但是常见错误将一个小的负整数分配给一个无符号类型的变量,最后得到一个非常大的正整数。
这个技巧实际上被用于边界检查:如果你有一个有符号整数i
,并想知道它是否在0< = i< n,你可以测试
if ((unsigned)i < n) { ... }
使用一个比较而不是两个来给出答案。演员到无人签名没有运行时成本;它只是告诉编译器生成无符号比较而不是签名比较。
答案 2 :(得分:2)
问题是你在 unsigned int中存储了-4。无符号整数只能包含零和正值。如果你将-4分配给一个,你实际上最终得到一个非常大的正数(实际值取决于你使用的int的宽度)。
答案 3 :(得分:2)
问题在于unsigned int
等存储空间的大小只能容纳这么多。使用1和-5无关紧要,但使用1和-500000000可能会导致混乱的结果。此外,unsigned
存储会将存储在其中的任何内容解释为正数,因此您无法在unsigned
变量中添加负值。
需要注意的两件大事:
1.操作本身溢出:1 + -500000000
2.投射问题:(unsigned int)(1 + -500)
答案 4 :(得分:0)
根据定义 ,号码-4
无法在unsigned int
中表示。 -4
是有符号整数。任何负数也是如此。
当您为unsigned int
分配负整数时,该数字的实际位数不会更改,但它们仅以表示不同。由于整数在二进制(two's complement)中的表示方式,你会得到一些可笑的大数。
在二进制补码中,-4
表示为0xfffffffc
。当0xfffffffc
表示为unsigned int
时,您将获得数字4,294,967,292
。
答案 5 :(得分:0)
无符号变量(如unsigned int)不能保存负值。因此,将1 - 5分配给unsigned int将不会给你-4。我不确定它会给你什么,它可能是特定于编译器的。
答案 6 :(得分:0)
一些代码:
signed int first, second;
unsigned int result;
first = obtain(); // happens to be 1
second = obtain(); // happens to be -5
result = first + second; // unexpected result here - very large number - and it's too late to check that there's a problem
假设您从键盘获取了这些值。您需要在添加之前检查结果是否可以用unsigned int表示。这就是文章所说的内容。
答案 7 :(得分:0)
你必须记住,从根本上说你正在使用比特。因此,您可以将值-4分配给无符号整数,这会将一系列位放入该内存位置。在某些情况下,这些位可以解释为-4 。一个这样的情况是显而易见的:你已告诉编译器/系统该存储器位置中的位应被解释为两个符号签名号。因此,如果你做printf(“%s”,i)prtinf发挥其魔力并将两个恭维数转换为幅度和符号。幅度为4,符号为负,因此显示“-4”。
但是,如果您告诉编译器该内存位置的数据未签名,则位不会更改,而是其解释。因此,当您进行添加时,将结果存储在无符号整数存储器位置,然后在结果上调用printf,它不会在寻找符号,因为根据定义它始终是正数。它计算幅度并打印出来。幅度将关闭,因为符号信息仍然以比特编码,但它被视为幅度信息。