比较C中两个相等的无符号长字符串计算结果为false

比较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);

我是C语言的新手,正在玩它。所以我最终实现了斐波那契代码(迭代和递归)。我写了一个测试函数,它应该给我一个绿色(我的实现正常)或红色。它说我得到了正确的返回值,但它的状态是红色的。这两个值都应为无符号长。我正在用make在OSX上编译

#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;