比较C中两个相等的无符号长字符串计算结果为false
我是C语言的新手,正在玩它。所以我最终实现了斐波那契代码(迭代和递归)。我写了一个测试函数,它应该给我一个绿色(我的实现正常)或红色。它说我得到了正确的返回值,但它的状态是红色的。这两个值都应为无符号长。我正在用make在OSX上编译比较C中两个相等的无符号长字符串计算结果为false,c,comparison,long-integer,unsigned,C,Comparison,Long Integer,Unsigned,我是C语言的新手,正在玩它。所以我最终实现了斐波那契代码(迭代和递归)。我写了一个测试函数,它应该给我一个绿色(我的实现正常)或红色。它说我得到了正确的返回值,但它的状态是红色的。这两个值都应为无符号长。我正在用make在OSX上编译 #include <stdio.h> unsigned long fibonacci(unsigned long n); void test_fibonacci(unsigned long n, unsigned long assertion);
#include <stdio.h>
unsigned long fibonacci(unsigned long n);
void test_fibonacci(unsigned long n, unsigned long assertion);
int main(int argc, char* argv[])
{
test_fibonacci(1, 1);
test_fibonacci(2, 1);
test_fibonacci(3, 2);
test_fibonacci(10, 55);
return 0;
}
unsigned long fibonacci(unsigned long n)
{
unsigned long result = 1;
unsigned long lastResult;
for (unsigned long i = 2; i <= n; i++)
{
// save the current result to save it as the lastResult after this iteration
unsigned long lastResultTmp = result;
result = lastResult + result;
lastResult = lastResultTmp;
}
return result;
}
void test_fibonacci(unsigned long n, unsigned long assertion)
{
printf(
"fibonacci(%lu): %lu | %s | asserted: %lu\n",
n,
fibonacci(n),
(fibonacci(n) == assertion) ? "green" : "red",
assertion
);
}
输出:
fibonacci(1): 1 | green | asserted: 1
fibonacci(2): 1 | red | asserted: 1
fibonacci(3): 2 | red | asserted: 2
fibonacci(10): 55 | red | asserted: 55
我没有得到你那样的结果。以下是我看到的:
fibonacci(1): 1 | green | asserted: 1
fibonacci(2): 2 | red | asserted: 1
fibonacci(3): 4 | red | asserted: 2
fibonacci(10): 3353 | red | asserted: 55
我很好奇为什么,所以我和valgrind一起运行了它。很快就出现了这个错误:
==5619== Conditional jump or move depends on uninitialised value(s)
==5619== at 0x4005E7: test_fibonacci (fibonacci.c:31)
==5619== by 0x400559: main (fibonacci.c:9)
看起来这与读取未初始化的变量有关,这会给您错误的值。这最终向我们指出:
unsigned long fibonacci(unsigned long n)
{
unsigned long result = 1;
unsigned long lastResult; // <---- LOOK HERE
for (unsigned long i = 2; i <= n; i++)
{
// save the current result to save it as the lastResult after this iteration
unsigned long lastResultTmp = result;
result = lastResult + result;
lastResult = lastResultTmp;
}
return result;
}
所以看起来需要初始化该值。因为该值对应于前面的斐波那契数,所以应该初始化为零。这样做会使所有测试都通过
现在,到底发生了什么事情,使你看起来得到了正确的答案,但仍然失败?请注意,在测试代码中调用了两次fibonacci
。我的猜测是,对fibonacci
的第一次调用(打印的那次调用)碰巧工作正常,因为出于某种原因,第一次调用的lastResult
中的值恰好为0。然而,我想第二次调用fibonacci
——与预期结果进行比较的调用——并没有返回与第一次调用相同的值,因为无论出于何种原因,lastResult
的值在第二次调用时不是0。这就是关于未定义行为的事情——像这样奇怪的事情可能会发生 fibonacci(1):1 |绿色|断言:1
斐波那契(2):3076653057 |红色|断言:1
斐波那契(3):3076653058 |红色|断言:2
斐波那契(10):1526988855 |红色|断言:55
我正在将此输出输出到您的代码中。我认为这是因为未初始化的变量lastResult。因为当我用0初始化它时,我得到了正确的结果。OP
这表明你的测试中有一个微妙的弱点。当调用fibonacci(n)
时,它提供了正确的答案。当调用(fibonacci(n)=断言)
时,它提供了错误的答案。缺点是您的测试代码每次测试调用两次而不是一次fibonacci(n)。由于您的代码有一个未初始化的变量:
使用UB(未定义的行为)-这是可能的
测试代码应该调用测试函数一次: 然后,至少通过错误的
test\u fibonacci()
,更可能得到一致的结果
OTOH,指出的这个弱点可能是一个优势,如果每个循环只调用一次测试fibonacci(),UB可能不会以一种糟糕的方式表现出来。非常感谢!这是完全正确的。由于第一个斐波那契数,我在for循环中将I设置为3,将lastResult设置为1。这解决了我的问题。我必须去看看valgrind。@noeden valgrind是一个很好的工具,当你开始的时候。我的建议是(1)在编译时一直启动警告设置,(2)将警告转化为错误,(3)在Valgrind中运行程序。你会惊讶地发现这样会犯下多少错误。:-)同意需要初始化
lastResult
,因为不这样做会导致UB。然而,我怀疑是其他原因导致OP得到了“正确”的答案,但未能进行比较。嗯。UB是UB。-->啊哈,fibonacci()
每隔一段时间为OP报告一次正确的答案。@chux我刚刚用一个合理的解释更新了我的答案。你觉得怎么样?同意-一个真正奇怪的UB。正如所指出的,它确实指出了OP测试中的一个弱点。OTOH,我对OP有一个合理的好的测试代码印象深刻。感谢你和OP,谢谢!我要改变这一点。
unsigned long fibonacci(unsigned long n)
{
unsigned long result = 1;
unsigned long lastResult; // <---- LOOK HERE
for (unsigned long i = 2; i <= n; i++)
{
// save the current result to save it as the lastResult after this iteration
unsigned long lastResultTmp = result;
result = lastResult + result;
lastResult = lastResultTmp;
}
return result;
}
result = lastResult + result;
// unsigned long lastResult; // bad
unsigned long lastResult = 0; // good
unsigned long f = fibonacci(n);
printf("fibonacci(%lu): %lu | %s | asserted: %lu\n",
n, f, (f == assertion) ? `"green" : "red", assertion;