在C语言中,为什么
n++
的执行速度比 n=n+1
快?(int n=...; n++;)
(int n=...; n=n+1;)
这是今天我们老师在课堂上提出的问题。(这不是作业)
n++
的执行速度比 n=n+1
快?(int n=...; n++;)
(int n=...; n=n+1;)
这是今天我们老师在课堂上提出的问题。(这不是作业)
如果你正在使用一个"石器时代"的编译器,那么这是正确的......
在"石器时代"中:
++n
比n++
快,而n++
又比n=n+1
快。
计算机通常有增加x
以及将常量加到x上
n++
,你只需要2次内存访问(读n、加n、写n)n=n+1
,你需要3次内存访问(读n、读常量、将n和常量相加、写n)但是今天的编译器会自动将n=n+1
转换为++n
,它会做更多超出你想象的事情!!
此外,在今天的乱序处理器上 - 即使是"石器时代"的编译器,许多情况下运行时间完全不会受影响!
++n
和n++
速度完全相同,与load-increment-store无关,你会看到唯一的速度差异取决于n是存储在寄存器还是内存中(不是n现在是否在寄存器中,而是它分配的存储是否在寄存器中),例如move (n)+,r0
将n移动到寄存器零中,并在移动后递增n。(VAX-11汇编) - Stephen Pn++
转换为 n=n+1
,然后在 -O2 中将其优化为一条指令的加法。n++
更快,只适用于非常旧的、不进行优化的编译器,这些编译器没有足够智能来选择适合 n = n + 1
的原地更新指令。这些编译器在PC世界已经过时多年,但可能仍可在奇怪的专有嵌入式平台上找到。int n;
void nplusplus() {
n++;
}
void nplusone() {
n = n + 1;
}
输出汇编代码(未经过优化):
.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
优化等级为-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
编译器会将 n + 1
优化成空值。
您是指 n = n + 1
吗?
如果是这样,它们将编译为相同的汇编代码。(假设开启了优化,并且它们是语句而不是表达式)
volatile
对于 ++n
和 n=n+1
之间没有任何区别。两者都会导致一次读取和一次写入,而且都不是原子操作。如果你想要原子性,volatile
无法提供;请等待 C1x 中的 _Atomic
类型。 - R.. GitHub STOP HELPING ICEvolatile
提供原子性,但如果平台能够在硬件寄存器上执行一些原子操作而不支持C11原子所需的所有操作中的所有操作,则记录实现涉及volatile
的一些构造以原子方式似乎是提供此类支持的最实用方法。比必须以破碎的方式实现所有操作且无法以硬件支持的有用方式实现任何操作的原子类型要好得多。 - supercat实际上并没有。编译器会根据目标架构进行特定的更改。这样微小的优化通常效果不明显,但重要的是,肯定不值得程序员花费时间。
++n
将增加 "n" 并返回对 "n" 的引用,而 n++
将增加 "n" 并返回 "n" 的 const
副本。 因此,短语 n = n + 1
将更有效率。但我必须同意以上评论者们的观点。好的编译器应该能够优化未使用的返回对象。n++
的副作用“根据定义”等价于表达式n = n + 1
的副作用。由于您的代码仅依赖于副作用,因此很明显这两个表达式的性能完全相同。(顺便提一下,无论编译器的优化设置如何,问题绝对与任何优化无关)。+
应该被实现为ADD,++
应该通过INC实现的内容。 - AnT stands with Russia我觉得这更像是一个硬件问题,而不是软件问题... 如果我没记错的话,在旧的CPU中,n=n+1需要两个内存位置,而++n只是一个微控制器命令... 但我怀疑这是否适用于现代架构...
a
比b
快"(其中a
和b
是 C 表达式)。只有在硬件c
上,使用编译器e
的版本d
和优化标志f
编译时才有意义地说 "a
比b
快"(以及其他一些要求)。 - Stephen Canonn++
比n = n + 1
更快,为什么?”这比仅仅关闭问题而没有讨论要有建设性得多 :) - bdonlan