在网站上阅读一些问题时,我遇到了问题需要调试的问题
unsigned int a, b, c;
/* a and b are assume to have some values */
c = (a + b) / 2; // <- There is a bug in this st
What is the bug? and how you debug it?
有些答案说它可能导致溢出(c =(a + b)/ 2)。但是真的没有得到它如何导致溢出?
答案 0 :(得分:8)
a+b
和a
的总和大于b
(UINT_MAX
的最大值),则 unsigned int
可能会溢出。如,
unsigned a = 1;
unsigned b = UINT_MAX;
printf("%u\n", (a+b)/2);
打印0
。
如果你想找到没有溢出的两个unsigned int
的平均值,请执行
c = a/2 + b/2 + (a % 2 & b % 2);
(或(a%2 + b%2)/2
,或(a%2 && b%2)
,或((a&1) & (b&1))
等。)
答案 1 :(得分:5)
如果a
和/或b
非常大,则a + b
可能超过无符号整数的最大大小(请参阅limits.h
文件中的MAX_UINT
)。这会导致溢出,因此结果是错误的。例如,如果a
和b
都等于0x80000000,则结果在32位算术中为0,而不是预期的结果0x80000000。
要解决这个问题,你可以使用类似的东西:
c = a/2 + b/2 + (a % 2 == 1 && b % 2 == 1);
如果您知道b
大于a
,那么您可以使用这个稍微简单的版本:
c = a + (b - a) / 2;
阅读这篇文章,了解有关此漏洞如何以可能流行的语言出现在二进制搜索算法中的信息(尽管它讨论的是signed int
而不是unsigned int
):
答案 2 :(得分:2)
正如其他人所说:
unsigned int a, b, c;
c = (a + b) / 2;
对于a + b
和unsigned int
的某些值, a
在b
中无法表示。
非常类似的情况导致了标准Java二进制搜索实现(binarySearch
函数)中的一个着名错误。
请参阅2006年着名的Joshua Blosh博客文章:
“额外,额外 - 阅读所有关于它:几乎所有的二进制搜索和合并都是破碎的” http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
摘录:
错误就在这一行:
6:int mid =(low + high)/ 2;
进一步向下:
那么修复bug的最佳方法是什么?这是一种方式:
6:int mid = low +((high - low)/ 2);
请注意,在Joshua帖子中,high
为>= low
,并且还使用了int
个对象,但Java将签名溢出视为包装。在C签名中,整数溢出是未定义的行为和未签名的环绕。
答案 3 :(得分:0)
如果a
和b
足够高,可能会导致溢出a + b
高于unsigned int
可表示的最大值。
答案 4 :(得分:0)
如果你只是在C中声明一个变量而没有初始化它,它会得到一个不可预测的值。 a和b可以是当前在内存中的地址的某个值。
您可以在Eclipse CDT中调试C代码 http://www.eclipse.org/cdt/
使用此IDE,您可以使用C anc C ++编程,它包含GDB调试器。
http://www.gnu.org/software/gdb/