这是我的代码:
int f(double x)
{
return isnan(x);
}
如果我添加#include <cmath>
,我会得到这个汇编代码:
xorl %eax, %eax
ucomisd %xmm0, %xmm0
setp %al
这是相当巧妙的:ucomisd会在x与其自身比较无序(即x为NAN)时设置奇偶标志位。然后setp将奇偶标志复制到结果(仅一个字节,因此初始清除%eax
)。
但是如果我包含 #include <math.h>
,我得到这个汇编:
jmp __isnan
现在代码不再是内联的,而且__isnan
函数肯定比ucomisd
指令慢,所以我们因为没有任何好处而产生了一个跳转。如果我将代码编译为C,我得到的结果是一样的。
现在,如果我将isnan()
调用更改为__builtin_isnan()
,则无论我包含哪个头文件,都会获得简单的ucomisd
指令,并且它也适用于C。同样,如果我只需要return x != x
。
所以我的问题是,为什么C语言的<math.h>
头文件提供的isnan()
实现比C++的<cmath>
头文件提供的实现效率低呢?人们真的期望使用__builtin_isnan()
吗?如果是这样,为什么?
我在x86-64上测试了GCC 4.7.2和4.9.0,并使用了-O2
和-O3
优化。
<math.h>
这样的系统头文件肯定可以使用特定于平台的内置函数。 - John Kugelmanisnan
会使用__builtin_isnan
。我看不出为什么你必须手动调用它。 - Rapptz