考虑以下C代码(假设为80位long double)(注意,我知道memcmp,这只是一个实验):
enum { sizeOfFloat80=10 }; // NOTE: sizeof(long double) != sizeOfFloat80
_Bool sameBits1(long double x, long double y)
{
    for(int i=0;i<sizeOfFloat80;++i)
        if(((char*)&x)[i]!=((char*)&y)[i])
            return 0;
    return 1;
}
我检查的所有编译器(gcc,clang,icc on gcc.godbolt.org)生成类似的代码,这里是gcc选项的示例-O3 -std=c11 -fomit-frame-pointer -m32:
sameBits1:
        movzx   eax, BYTE PTR [esp+16]
        cmp     BYTE PTR [esp+4], al
        jne     .L11
        movzx   eax, BYTE PTR [esp+17]
        cmp     BYTE PTR [esp+5], al
        jne     .L11
        movzx   eax, BYTE PTR [esp+18]
        cmp     BYTE PTR [esp+6], al
        jne     .L11
        movzx   eax, BYTE PTR [esp+19]
        cmp     BYTE PTR [esp+7], al
        jne     .L11
        movzx   eax, BYTE PTR [esp+20]
        cmp     BYTE PTR [esp+8], al
        jne     .L11
        movzx   eax, BYTE PTR [esp+21]
        cmp     BYTE PTR [esp+9], al
        jne     .L11
        movzx   eax, BYTE PTR [esp+22]
        cmp     BYTE PTR [esp+10], al
        jne     .L11
        movzx   eax, BYTE PTR [esp+23]
        cmp     BYTE PTR [esp+11], al
        jne     .L11
        movzx   eax, BYTE PTR [esp+24]
        cmp     BYTE PTR [esp+12], al
        jne     .L11
        movzx   eax, BYTE PTR [esp+25]
        cmp     BYTE PTR [esp+13], al
        sete    al
        ret
.L11:
        xor     eax, eax
        ret
这看起来很难看,在每个字节上都有分支,实际上似乎根本没有进行优化(但至少循环是展开的).很容易看出,这可以针对与以下代码等效的代码进行优化(通常对于使用更大步幅的更大数据):
#include <string.h>
_Bool sameBits2(long double x, long double y)
{
    long long X=0; memcpy(&X,&x,sizeof x);
    long long Y=0; memcpy(&Y,&y,sizeof y);
    short Xhi=0; memcpy(&Xhi,sizeof x+(char*)&x,sizeof Xhi);
    short Yhi=0; memcpy(&Yhi,sizeof y+(char*)&y,sizeof Yhi);
    return X==Y && Xhi==Yhi;
}
而且这段代码现在得到了更好的编译结果:
sameBits2:
        sub     esp, 20
        mov     edx, DWORD PTR [esp+36]
        mov     eax, DWORD PTR [esp+40]
        xor     edx, DWORD PTR [esp+24]
        xor     eax, DWORD PTR [esp+28]
        or      edx, eax
        movzx   eax, WORD PTR [esp+48]
        sete    dl
        cmp     WORD PTR [esp+36], ax
        sete    al
        add     esp, 20
        and     eax, edx
        ret
所以我的问题是:为什么三个编译器中没有一个能够进行这种优化?它在C代码中看到的非常罕见吗?
首先,它无法进行此优化,因为您通过使用过多的内存重新解释来重载代码,从而完全模糊了代码的含义.像这样的代码只是让编译器做出反应"我不知道这是什么,但如果这就是你想要的,那就是你将得到的".为什么你期望编译器甚至懒得将内存重新解释转换为另一种内存重新解释(!)对我来说完全不清楚.
其次,它可能在理论上可以做到,但它的优先级列表可能不是很高.请记住,代码优化通常通过模式匹配算法完成,而不是通过某种AI来完成.这不是它识别的模式之一.
大多数情况下,您的手动尝试执行代码的低级优化将使编译器无法完成同样的工作.如果你想自己优化它,那就一直走.不要指望能够启动然后将其交给编译器为您完成工作.
两个比较long double值,x并且y可以很容易地做到:x == y.如果你想要一个比特到内存的比较,你可能只需要memcmp在一个本质上知道什么memcmp是内置的编译器(内置函数)中使用,就可以简化编译器的工作.