为什么比较两次char变量比一次比较短变量要快

时间:2013-12-25 09:48:07

标签: c++ c performance assembly

我认为一个比较必须快于两个。但经过我的测试,我发现在调试模式下,短比较快一点,而在发布模式下,char比较速度更快。我想知道真正的原因。

以下是测试代码和测试结果。我写了两个简单的函数,func1()使用两个char比较,func2()使用一个简短的比较。 main函数返回临时返回值,以避免编译优化忽略我的测试代码。我的编译器是GCC 4.7.2,CPU英特尔®至强®CPUE5-2430 0 @ 2.20GHz(VM)。

inline int func1(unsigned char word[2])
{
        if (word[0] == 0xff && word[1] == 0xff)
                return 1;
        return 0;
}

inline int func2(unsigned char word[2])
{
        if (*(unsigned short*)word == 0xffff)
                return 1;
        return 0;
}

int main()
{
        int n_ret = 0;
        for (int j = 0; j < 10000; ++j)
                for (int i = 0; i < 70000; ++i)
                        n_ret += func2((unsigned char*)&i);
        return n_ret;
}

调试模式:

          func1      func2
real    0m3.621s    0m3.586s
user    0m3.614s    0m3.579s
sys     0m0.001s    0m0.000s

发布模式:

          func1      func2
real    0m0.833s    0m0.880s
user    0m0.831s    0m0.878s
sys     0m0.000s    0m0.002s

func1版的汇编代码:

        .cfi_startproc
        movl    $10000, %esi
        xorl    %eax, %eax
        .p2align 4,,10
        .p2align 3
.L6:
        movl    $1, %edx
        xorl    %ecx, %ecx
        .p2align 4,,10
        .p2align 3
.L8:
        movl    %edx, -24(%rsp)
        addl    $1, %edx
        addl    %ecx, %eax
        cmpl    $70001, %edx
        je      .L3
        xorl    %ecx, %ecx
        cmpb    $-1, -24(%rsp)
        jne     .L8
        xorl    %ecx, %ecx
        cmpb    $-1, -23(%rsp)
        sete    %cl
        jmp     .L8
        .p2align 4,,10
        .p2align 3
.L3:
        subl    $1, %esi
        jne     .L6
        rep
        ret
        .cfi_endproc

func2版的汇编代码:

        .cfi_startproc
        movl    $10000, %esi
        xorl    %eax, %eax
        .p2align 4,,10
        .p2align 3
.L4:
        movl    $1, %edx
        xorl    %ecx, %ecx
        jmp     .L3
        .p2align 4,,10
        .p2align 3
.L7:
        movzwl  -24(%rsp), %ecx
.L3:
        cmpw    $-1, %cx
        movl    %edx, -24(%rsp)
        sete    %cl
        addl    $1, %edx
        movzbl  %cl, %ecx
        addl    %ecx, %eax
        cmpl    $70001, %edx
        jne     .L7
        subl    $1, %esi
        jne     .L4
        rep
        ret
        .cfi_endproc

1 个答案:

答案 0 :(得分:3)

在GCC 4.6.3中,第一段和第二段代码的代码是不同的,如果你运行它足够长的话,func1选项的运行时间会明显变慢。不幸的是,由于运行时间很短,两者在时间上看起来相似。

将外循环增加10倍意味着func2需要大约6秒,func1需要10秒。这是使用gcc -std=c99 -O3来编译代码。

我期望的主要区别在于&amp;&amp; amp;声明。额外的xorl %ecx, %ecx没有多大帮助(我得到了同样的结论,尽管我的代码在标签名称方面看起来略有不同)。

编辑:我确实尝试使用and而不是分支来提出无分支解决方案,但编译拒绝内联函数,因此需要30秒而不是10秒。

基准测试:

AMD Phenom(tm) II X4 965

以3.4 GHz运行。