当指数改变时出现“未定义的引用pow”?

6
我遇到了一些关于 pow() 的奇怪问题。如果我这样做:

return 44330*(1 - pow((float) pressure / PRESSURE0, 1/5.255F));

其中 pressure 是一个 int32_t 类型,而 PRESSURE0 则是一个常量,我会收到一个错误,提示“未定义对 `pow' 的引用”。然而,如果我这样做:

return 44330*(1 - pow((float) pressure / PRESSURE0, 1.0F));

就没有问题。我做错了什么吗?

谢谢!


请在您的编译器选项中尝试使用 -lm。 - user411313
2
这很可能是编译器优化引起的:在第二种情况下,由于指数为1.0,因此无需调用pow()函数。要修复第一种变体,请尝试使用-lm链接。另请参见https://dev59.com/XGLVa4cB1Zd3GeqPtBYy和https://dev59.com/AHI-5IYBdhLWcg3wBjnk。 - Andreas Fester
我不认为这个-lm选项可以解决这个问题 - 他的第二个示例可以工作,我假设它编译相同。@Kate - 你在使用C++编译器吗?你能提供你用于pow的make文件和头文件吗? - Ishay Peled
1
@IshayPeled 复现它。你会看到和 OP 一样的问题。请看下面我的回答。 - Andreas Fester
1个回答

7

通常,如果要使用诸如sqrt()pow()等数学函数,则需要链接数学库libm(在gcc上,请使用-lm选项)。

但是,编译器可以自由地应用优化,特别是当函数的参数为常量时。考虑以下两个简化的函数:

double f1(int pressure) {
   return pow((float) pressure / PRESSURE0, 1/5.255F);
}

double f2(int pressure) {
   return pow((float) pressure / PRESSURE0, 1.0F);
}

这将被编译成i386代码,如下所示(删除了不必要的汇编指令):
f1:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp

; (float) pressure / PRESSURE0
        fildl   8(%ebp)
        fldl    .LC0
        fdivrp  %st, %st(1)

; pow()
        fldl    .LC1
        fstpl   8(%esp)
        fstpl   (%esp)
        call    pow

        leave
        ret

f2:
        pushl   %ebp
        movl    %esp, %ebp

; (float) pressure / PRESSURE0
        fildl   8(%ebp)
        fldl    .LC0
        fdivrp  %st, %st(1)

; NO call to pow(x, 1.0), since it would not change the value of x

        popl    %ebp
        ret

f2()中,由于幂运算的指数是1.0,因此没有必要调用pow()函数 - 编译器会检测到这一点并删除函数调用。因此,如果您的代码中没有其他对任何数学函数的调用,则在这种特殊情况下不需要链接libm
另请参见:

2
顺便提一下:这就是为什么函数未定义引用被标准视为未定义行为,无需诊断的原因:这样编译器就可以进行优化,而不必保留其优化掉了什么的记录。 - M.M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接