若是不使用结果值, i++
和++i
之间会有性能差别吗? 程序员
请不要让“哪一个更快”的问题成为使用哪一个的决定因素。 您永远都不会在意那么多,此外,程序员的阅读时间比机器学习的时间要昂贵得多。 机器学习
使用对人类阅读代码最有意义的方法。 函数
我老是喜欢预增量,可是... 性能
我想指出的是,即便在调用operator ++函数的状况下,若是函数被内联,编译器也将可以优化掉临时函数。 因为operator ++一般很短,而且常常在标头中实现,所以极可能会内联。 学习
所以,出于实际目的,这两种形式的性能可能没有太大区别。 可是,我老是更喜欢预增量,由于直接表达我想说的彷佛更好,而不是依靠优化器来解决。 优化
一样,减小优化器的工做量可能意味着编译器运行得更快。 spa
我能够想到后缀比前缀增量慢的状况: code
想象一下,将具备寄存器A
的处理器用做累加器,而且它是许多指令中使用的惟一寄存器(某些小型微控制器实际上就是这样)。 对象
如今,假设如下程序及其转换为假设的程序集: 内存
前缀增量:
a = ++b + c; ; increment b LD A, [&b] INC A ST A, [&b] ; add with c ADD A, [&c] ; store in a ST A, [&a]
后缀增量:
a = b++ + c; ; load b LD A, [&b] ; add with c ADD A, [&c] ; store in a ST A, [&a] ; increment b LD A, [&b] INC A ST A, [&b]
请注意b
的值是如何被强制从新加载的。 使用前缀递增,编译器能够只递增该值并继续使用它,可能避免从新加载它,由于所需的值在递增以后已经存在于寄存器中。 可是,使用后缀增量,编译器必须处理两个值,一个是旧值,另外一个是增量值,正如我在上面显示的那样,这将致使更多的内存访问。
固然,若是不使用增量值,例如单个i++;
语句,不管后缀或前缀使用状况如何,编译器均可以(而且确实)简单地生成增量指令。
附带说明一下,我想提到一个存在b++
的表达式不能简单地用++b
转换为一个表达式而无需任何额外的努力(例如,经过添加- 1
)。 所以,若是将二者做为某个表达式的一部分,则将它们进行比较是不正确的。 一般,在表达式中使用b++
状况下,不能使用++b
,所以即便++b
可能更有效,也彻底是错误的。 若是表达式请求它,固然是例外(例如a = b++ + 1;
能够更改成a = ++b;
)。
首先:在C中, i++
和++i
之间的区别能够忽略不计。
到细节。
++i
更快 在C ++中,若是i
是某种带有重载增量运算符的对象,则++i
效率更高。
为何?
在++i
,对象首先增长,而后能够做为const引用传递给任何其余函数。 若是表达式是foo(i++)
这是不可能的,由于如今须要在调用foo()
以前完成增量,可是须要将旧值传递给foo()
。 所以,在对原始文件执行增量运算符以前,编译器被迫复制i
。 额外的构造函数/析构函数调用是最糟糕的部分。
如上所述,这不适用于基本类型。
i++
可能会更快 若是不须要调用构造函数/析构函数,这在C ++i
老是如此, ++i
和i++
应该同样快,对吗? 不。它们的速度几乎同样快,但可能会有一些细微的差别,大多数其余应答者都采用了错误的方法。
如何能i++
更快?
关键是数据依赖性。 若是须要从内存中加载该值,则须要对其进行两个后续操做,使其递增并使用它。 对于++i
,须要先进行递增, 而后才能使用该值。 使用i++
,使用不取决于增量,CPU能够与增量操做并行执行使用操做。 区别最可能是一个CPU周期,所以它确实能够忽略不计,可是确实存在。 这是许多人指望的另外一种方式。
内容提要:否。
i++
可能比++i
慢,由于可能须要保存i
的旧值以供之后使用,但实际上全部现代编译器都会对其进行优化。
咱们能够经过使用++i
和i++
查看此函数的代码来证实这一点。
$ cat i++.c extern void g(int i); void f() { int i; for (i = 0; i < 100; i++) g(i); }
这些文件是相同的,除了++i
和i++
:
$ diff i++.c ++i.c 6c6 < for (i = 0; i < 100; i++) --- > for (i = 0; i < 100; ++i)
咱们将对其进行编译,并得到生成的汇编器:
$ gcc -c i++.c ++i.c $ gcc -S i++.c ++i.c
咱们能够看到生成的对象文件和汇编文件都是相同的。
$ md5 i++.s ++i.s MD5 (i++.s) = 90f620dda862cd0205cd5db1f2c8c06e MD5 (++i.s) = 90f620dda862cd0205cd5db1f2c8c06e $ md5 *.o MD5 (++i.o) = dd3ef1408d3a9e4287facccec53f7d22 MD5 (i++.o) = dd3ef1408d3a9e4287facccec53f7d22