【问题标题】:C function changes behaviour depending on whether it has a call to printf in it [closed]C函数根据它是否调用printf来改变行为[关闭]
【发布时间】:2010-03-15 13:47:10
【问题描述】:

我有一个函数可以处理一些数据并找到对具有最低错误的数据进行分类的阈值。它看起来像这样:

void find_threshold(FeatureVal* fvals, sampledata* data, unsigned int num_samples, double* thresh, double* err, int* pol) {
    //code to calculate minThresh, minErr, minPol omitted
    printf("minThresh: %f, minErr: %f, minPol: %d\n", minThresh, minErr, minPol);
    *thresh = minThresh;
    *err = minErr;
    *pol = minPol;
}

然后在我的测试文件中我有这个:

void test_find_threshold() {
    //code to set up test data omitted
    find_threshold(fvals, sdata, 6, &thresh, &err, &pol);

    printf("Expected 5 got %f\n", thresh);
    assert(eq(thresh, 5.0));
    printf("Expected 1 got %d\n", pol);
    assert(pol == 1);
    printf("Expected 0 got %f\n", err);
    assert(eq(err, 0.0));
}

运行,测试通过,输出如下:

minThresh: 5.000000, minErr: 0.000000, minPol: 1
Expected 5 got 5.000000
Expected 1 got 1
Expected 0 got 0.000000

但是,如果我从 find_threshold 中删除对 printf() 的调用,测试会突然失败!注释掉断言以便我可以看到返回的内容,输出是:

Expected 5 got -15.000000
Expected 1 got -1
Expected 0 got 0.333333

我无法理解这一点。

【问题讨论】:

  • 问题可能出在你省略的代码中(//省略了计算minThresh、minErr、minPol的代码)
  • 你写的第一眼看起来不错,所以实际的错误可能在于你省略的代码。您确定当您删除printf 调用时,它之后的代码仍在执行吗?您可以在源代码级调试器(例如 gdb)中运行它吗?
  • 在哪里以及如何定义 minThresh、minErr、minPol?
  • 这可能是一个优化器错误。我会尝试在禁用所有优化的情况下进行编译,看看问题是否仍然存在。
  • 在发布到 SO 之前不要从测试用例中删除代码!你应该做的是编写一个最小的测试用例——你无法解释——然后发布。更多建议:sscce.orgxs4all.nl/~weegen/eelis/iso-c++/testcase.xhtml

标签: c printf


【解决方案1】:

printf 可以拨打malloc。因此,如果您有一些悬空指针,调用printf 可以更改这些指针指向的值。如果您的程序严格遵守,那么在调用printf 时您不会观察到这种差异(正如您所期望的那样)。在最坏的情况下,printf 中的分配可能会失败,但不会默默地破坏其他变量。

【讨论】:

  • 要对此进行测试,请将您的 printf 调用移到最后一个赋值语句的下方。这样,如果printf 正在更改任何内容,它将在函数的“重要部分”发生之后发生。
【解决方案2】:

我怀疑内存访问/分配存在问题,并使用valgrind 进行测试

【讨论】:

  • 我通过 valgrind 运行它,它告诉我函数中有一些未初始化的变量。我找到了罪魁祸首(我用来保持累积总和的一对双打)并正确初始化它们,现在它可以工作了。所以现在我知道为什么我的代码给出了错误的答案 - 但我仍然对调用 printf 如何让它给出正确的答案感到困惑!
  • 我能想到的唯一方法是查看生成的汇编代码。您是否进行了优化编译?也许 printf 使一些变量分配在堆栈上而不是寄存器上,结果是不同的(可能是幸运的,因为变量被统一化了)
  • David 的最后一条评论对我来说似乎是正确的 - 因为 printf 调用会破坏寄存器,添加它会更改调用函数中对寄存器/内存的变量分配。
猜你喜欢
  • 2021-06-05
  • 1970-01-01
  • 2015-06-12
  • 2011-05-03
  • 1970-01-01
  • 1970-01-01
  • 2021-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多