n = 0和n = n - n之间的差异

sha*_*kin 3 c compiler-construction optimization assembly

当我读到这个问题时,我记得有人告诉过我(多年前),从装配者的角度来看,这两个操作是非常不同的:

n = 0;

n = n - n;
Run Code Online (Sandbox Code Playgroud)

这是真的,如果是的话,为什么会这样呢?

编辑:正如一些回复所指出的,我想这对于编译器优化到同一个东西来说相当容易.但我觉得有趣的是,如果编译器采用完全通用的方法,它们会有所不同.

tan*_*ius 10

编写经常使用的汇编程序代码:

xor eax, eax
Run Code Online (Sandbox Code Playgroud)

代替

mov eax, 0
Run Code Online (Sandbox Code Playgroud)

这是因为第一个语句只有操作码而没有参数.你的CPU将在1 cylce(而不是2)中完成.我认为你的情况类似(虽然使用sub).


小智 7

编译VC++ 6.0,没有优化:

4:        n = 0;
0040102F   mov         dword ptr [ebp-4],0
5:
6:        n = n - n;
00401036   mov         eax,dword ptr [ebp-4]
00401039   sub         eax,dword ptr [ebp-4]
0040103C   mov         dword ptr [ebp-4],eax
Run Code Online (Sandbox Code Playgroud)


Eli*_*sky 6

优化编译器将为两者生成相同的汇编代码。


Aar*_*lla 6

在早期,内存和 CPU 周期很少。这导致了许多所谓的“窥视孔优化”。让我们看一下代码:

    move.l #0,d0

    moveq.l #0,d0

    sub.l a0,a0

第一条指令需要两个字节用于操作码,然后需要四个字节用于值 (0)。这意味着浪费了四个字节,而且您需要访问内存两次(一次用于操作码,一次用于数据)。慢点。

moveq.l更好,因为它将数据合并到操作码中,但它只允许将 0 到 7 之间的值写入寄存器。而且您仅限于数据寄存器,没有快速清除地址寄存器的方法。您必须清除数据寄存器,然后将数据寄存器加载到地址寄存器中(两个操作码。不好。)。

这导致对任何寄存器进行的最后一个操作,只需要两个字节,单个内存读取。翻译成C,你会得到

n = n - n;
Run Code Online (Sandbox Code Playgroud)

这适用于最常用的类型n(整数或指针)。

  • @RA:是的,nn 在 M68000 CPU 上的地址寄存器效率更高。Moveq.l 对于数据寄存器来说更快,因为 m68k 只有一个 16 位 ALU,但 sub.l 更通用。两者都需要 16 位内存。有趣的是, clr.l(将寄存器设置为 0)比 moveq.l 慢;) (2认同)

mou*_*iel 5

这可能取决于是否n声明为volatile