这样编译很好
#include <math.h>
int main(void) {
double i = sqrt(9.0);
}
如果我将 9.0 更改为 -9.0,那么我的编译器 (GNU C) 会给出一个关于对“sqrt”的 undefined reference 的错误。
我原以为 sqrt 函数会返回 NaN 或异常。 C 库如何只为非负参数定义 sqrt?
最佳答案
这是因为 gcc
可以在优化过程中使用 内置函数 在编译时计算某些函数,包括 sqrt
所有情况。如果是这种情况,它将不需要发出对 sqrt
的调用,因此不需要链接到 libm
。
gcc 文档有一个 complete list of builtins ,它说(强调我的):
The remaining functions are provided for optimization purposes.
GCC includes built-in versions of many of the functions in the standard C library. The versions prefixed with _builtin are always treated as having the same meaning as the C library function even if you specify the -fno-builtin option. (see C Dialect Options) Many of these functions are only optimized in certain cases; if they are not optimized in a particular case, a call to the library function is emitted.
如果我使用 gcc -S
编译此代码并查看我们使用 sqrt(9.0)
时发出的程序集 ( live example ) > 然后 gcc
将使用一个内置函数并且根本不会发出对 sqrt 的调用,因为它将在编译时计算它。如果我们将代码更改为使用 sqrt(-9.0)
,它现在将发出( live example ):
call sqrt
这将需要与 libm 链接,修复方法是将 -lm
添加到编译选项的末尾。
在 sqrt(-9)
的情况下,我们有一个域错误,如果转到 C99 草案标准部分 7.12.7.5
sqrt 函数 2 段说(强调我的):
The sqrt functions compute the nonnegative square root of x. A domain error occurs if the argument is less than zero.
如果我们回到 7.12.1
Treatment of error conditions 它说:
[...] On a domain error, the function returns an implementation-defined value; if the integer expression math_errhandling & MATH_ERRNO is nonzero, the integer expression errno acquires the value EDOM; if the integer expression math_errhandling & MATH_ERREXCEPT is nonzero, the ‘‘invalid’’ floating-point exception is raised.
因此将设置 errno 和/或将引发 float 异常,这似乎是 gcc
决定的情况优化效率不高。
关于c - sqrt 仅在参数为非负时定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20156285/