为什么GCC对C++ <cmath>比C <math.h>更有效地实现isnan()?

Joh*_*nck 42 c c++ optimization nan constantfolding

这是我的代码:

int f(double x)
{
  return isnan(x);
}
Run Code Online (Sandbox Code Playgroud)

如果我#include <cmath>得到这个集会:

xorl    %eax, %eax
ucomisd %xmm0, %xmm0
setp    %al
Run Code Online (Sandbox Code Playgroud)

这是相当聪明的:如果x与其自身的比较是无序的,则ucomisd设置奇偶校验标志,意味着x是NAN.然后setp将奇偶校验标志复制到结果中(只有一个字节,因此最初清除%eax).

但是,如果我#include <math.h>得到这个集会:

jmp     __isnan
Run Code Online (Sandbox Code Playgroud)

现在代码不是内联的,并且__isnan函数当然没有更快的ucomisd指令,所以我们已经跳过没有任何好处.如果我将代码编译为C,我会得到同样的东西.

现在如果我将isnan()调用更改为__builtin_isnan(),我会得到简单的ucomisd指令指令,无论我包含哪个头,它也可以在C中工作.同样,如果我只是return x != x.

所以我的问题是,为什么C <math.h>头提供的效率isnan()低于C++ <cmath>头?人们真的希望使用__builtin_isnan(),如果是,为什么?

我在x86-64上使用-O2-O3优化测试了GCC 4.7.2和4.9.0 .

Rap*_*ptz 17

查看<cmath>gcc 4.9附带的libstdc ++,你会得到:

  constexpr bool
  isnan(double __x)
  { return __builtin_isnan(__x); }
Run Code Online (Sandbox Code Playgroud)

一个constexpr功能可以积极内联,当然,该功能仅委派过工作__builtin_isnan.

<math.h>头不使用__builtin_isnan,而它使用的__isnan是一种长在这里贴上实现,但它是线430 math.h在我的机器上™.由于C99标准要求使用宏isnan等(C99标准的第7.12节),'功能'定义如下:

#define isnan(x) (sizeof (x) == sizeof (float) ? __isnanf (x)   \
  : sizeof (x) == sizeof (double) ? __isnan (x) \
  : __isnanl (x))
Run Code Online (Sandbox Code Playgroud)

但是,我认为没有理由不能使用它__builtin_isnan,__isnan所以我怀疑这是一种疏忽.正如Marc Glisse在评论中指出的那样,有一个相关的错误报告用于isinf代替类似的问题isnan.

  • 不要忘记包括[this](http://chat.stackoverflow.com/transcript/message/19109073#19109073)说标准*要求*它们是宏. (2认同)