在C中,i ++和++ i之间是否存在性能差别?

若是不使用结果值, i++++i之间会有性能差别吗? 程序员


#1楼

请不要让“哪一个更快”的问题成为使用哪一个的决定因素。 您永远都不会在意那么多,此外,程序员的阅读时间比机器学习的时间要昂贵得多。 机器学习

使用对人类阅读代码最有意义的方法。 函数


#2楼

我老是喜欢预增量,可是... 性能

我想指出的是,即便在调用operator ++函数的状况下,若是函数被内联,编译器也将可以优化掉临时函数。 因为operator ++一般很短,而且常常在标头中实现,所以极可能会内联。 学习

所以,出于实际目的,这两种形式的性能可能没有太大区别。 可是,我老是更喜欢预增量,由于直接表达我想说的彷佛更好,而不是依靠优化器来解决。 优化

一样,减小优化器的工做量可能意味着编译器运行得更快。 spa


#3楼

我能够想到后缀比前缀增量慢的状况: 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; )。


#4楼

首先:在C中, i++++i之间的区别能够忽略不计。


到细节。

1.众所周知的C ++问题: ++i更快

在C ++中,若是i是某种带有重载增量运算符的对象,则++i效率更高。

为何?
++i ,对象首先增长,而后能够做为const引用传递给任何其余函数。 若是表达式是foo(i++)这是不可能的,由于如今须要在调用foo()以前完成增量,可是须要将旧值传递给foo() 。 所以,在对原始文件执行增量运算符以前,编译器被迫复制i 。 额外的构造函数/析构函数调用是最糟糕的部分。

如上所述,这不适用于基本类型。

2.不为人知的事实: i++ 可能会更快

若是不须要调用构造函数/析构函数,这在C ++i老是如此, ++ii++应该同样快,对吗? 不。它们的速度几乎同样快,但可能会有一些细微的差别,大多数其余应答者都采用了错误的方法。

如何能i++更快?
关键是数据依赖性。 若是须要从内存中加载该值,则须要对其进行两个后续操做,使其递增并使用它。 对于++i ,须要先进行递增, 而后才能使用该值。 使用i++ ,使用不取决于增量,CPU能够与增量操做并行执行使用操做。 区别最可能是一个CPU周期,所以它确实能够忽略不计,可是确实存在。 这是许多人指望的另外一种方式。


#5楼

内容提要:否。

i++可能比++i慢,由于可能须要保存i的旧值以供之后使用,但实际上全部现代编译器都会对其进行优化。

咱们能够经过使用++ii++查看此函数的代码来证实这一点。

$ cat i++.c
extern void g(int i);
void f()
{
    int i;

    for (i = 0; i < 100; i++)
        g(i);

}

这些文件是相同的,除了++ii++

$ 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
相关文章
相关标签/搜索