为什么n ++的执行速度比n = n + 1快?

31 c optimization performance micro-optimization

在C语言中,为什么n++执行速度比n=n+1

(int n=...;  n++;)
(int n=...;  n=n+1;)
Run Code Online (Sandbox Code Playgroud)

我们的老师在今天的班上问了这个问题.(这不是作业)

Bet*_*moo 102

如果你正在研究一个"石器时代"的编译器,那将是真的......

在的情况下,"石器时代":
++n快于n++快于n=n+1
机床通常increment x以及add const to x

  • 在这种情况下n++,您将只有2个内存访问(读取n,包含,写入n)
  • 在这种情况下n=n+1,您将有3个内存访问(读取n,读取const,添加n和const,写入n)

但今天的编译器会自动转换n=n+1++n,它会比你想象的更多!

同样在今天的乱序处理器虽然依然的情况下,"石器时代"反编译运行时可能不会受到影响所有在许多情况下!

有关

  • @gcc:不,你不应该这么说.您应该说"两者之间应该没有任何区别.优化编译器已经处理了这样的事情数十年,因为至少Wiss等人在"设计优化编译器"中描述的Bliss-11编译器. (6认同)
  • 在计算机上我了解到这一点,`++ n`和`n ++`的速度完全相同,它不需要加载 - 增量 - 存储,你看到的唯一的速度差异取决于是否` n`存储在寄存器或存储器中(不是n当前是否恰好在寄存器中,而是其分配的存储是否在寄存器中)例如`move(n)+,r0`将n移动到寄存器0,移动后递增n.(VAX-11组装) (4认同)
  • +1用于以有用的方式实际回答问题,而不是仅仅说它们是相同的,这对于知道而非OP可能想要的信息是有用的. (2认同)
  • 说编译器将"将'n = n + 1`转换为'++ n`"是完全错误的,甚至是无意义的.这就像说翻译人员在将英语翻译成法语时会"将它变为````'.两者之间的区别是*源语言*的工件. (2认同)
  • 我被教导了.++ n可能更快,但永远不会慢于n ++.对于任何给定的硬件. (2认同)
  • 这是一个标准的C++课堂口号,已被转移到C并在此过程中变得毫无意义.请注意,在C中,没有将"++"运算符应用于"大而昂贵的复制数据类型".但即使有,也不涉及复制.在postincrement运算符之后的任何时间但在下一次使用值之前*,在当前表达式中使用该值之后很久就会发生增量. (2认同)

bdo*_*lan 42

在GCC 4.4.3 for x86上,无论是否进行优化,它们都会编译为完全相同的汇编代码,因此需要花费相同的时间来执行.正如您在程序集中看到的那样,GCC只需转换n++n=n+1,然后将其优化为单指令添加(在-O2中).

您的教师建议n++更快只适用于非常老的非优化编译器,这些编译器不够智能,无法选择就地更新指令n = n + 1.这些编译器已经在PC世界中淘汰多年,但仍可能出现在奇怪的专有嵌入式平台上.

C代码:

int n;

void nplusplus() {
    n++;
}

void nplusone() {
    n = n + 1;
}
Run Code Online (Sandbox Code Playgroud)

输出程序集(无优化):

    .file   "test.c"
    .comm   n,4,4
    .text
.globl nplusplus
    .type   nplusplus, @function
nplusplus:
    pushl   %ebp
    movl    %esp, %ebp
    movl    n, %eax
    addl    $1, %eax
    movl    %eax, n
    popl    %ebp
    ret
    .size   nplusplus, .-nplusplus
.globl nplusone
    .type   nplusone, @function
nplusone:
    pushl   %ebp
    movl    %esp, %ebp
    movl    n, %eax
    addl    $1, %eax
    movl    %eax, n
    popl    %ebp
    ret
    .size   nplusone, .-nplusone
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)

输出组件(带有-O2优化):

    .file   "test.c"
    .text
    .p2align 4,,15
.globl nplusplus
    .type   nplusplus, @function
nplusplus:
    pushl   %ebp
    movl    %esp, %ebp
    addl    $1, n
    popl    %ebp
    ret
    .size   nplusplus, .-nplusplus
    .p2align 4,,15
.globl nplusone
    .type   nplusone, @function
nplusone:
    pushl   %ebp
    movl    %esp, %ebp
    addl    $1, n
    popl    %ebp
    ret
    .size   nplusone, .-nplusone
    .comm   n,4,4
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)

  • 对于测试+1,GCC在`-O0`上非常愚蠢,但它仍然这样做...... (3认同)

SLa*_*aks 14

编译器将优化n + 1为虚无.

你的意思是n = n + 1

如果是这样,他们将编译成相同的程序集.(假设优化已经开启,而且它们是语句,而不是表达式)


小智 5

谁说它呢?你的编译器将它全部优化掉了,真的,使它成为一个没有实际意义的点.