通过编译器在从C源到asm实现的过程中所做的转换,你会感到困惑.gcc的输出以这种方式实现你的功能:
a = 5;
if (a<=2) goto ret0;
return 1;
ret0:
return 0;
Run Code Online (Sandbox Code Playgroud)
这一切都笨拙和多余的,因为你编译-O0,所以它存储a到内存中,然后重新加载它,所以你可以用一个调试器,如果你设置一个断点,仍然有码"工作"进行修改.
编译器通常更喜欢降低比较常量的大小,因此它更有可能适合符号扩展的8位立即数,而不需要在机器代码中立即使用32位立即数.
我们可以通过编写一个带有arg的函数来获得一些很好的紧凑代码,因此当我们启用优化时它不会被优化掉.
int cmp(int a) {
return a>=128; // In C, a boolean converts to int as 0 or 1
}
Run Code Online (Sandbox Code Playgroud)
gcc -O3在Godbolt上,针对x86-64 ABI(与您的代码相同):
xorl %eax, %eax # whole RAX = 0
cmpl $127, %edi
setg %al # al = (edi>127) : 1 : 0
ret
Run Code Online (Sandbox Code Playgroud)
所以它变成了>=128一个>127比较.这样可以节省3个字节的机器代码,因为cmp $127, %edi可以使用cmp $imm8, r/m32编码(cmp r/m32, imm8英特尔手册中的英特尔语法),但128必须使用cmp $imm32, r/m32.
顺便说一句,比较和条件在英特尔语法中是有意义的,但在AT&T语法中是倒退的.例如, cmp edi, 127/ jg如果edi > 127.
但是在AT&T语法中,它是cmp $127, %edi,所以你必须在心理上扭转操作数或想到一个>而不是<