我认为一个比较必须快于两个。但经过我的测试,我发现在调试模式下,短比较快一点,而在发布模式下,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
答案 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运行。