Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
i++;和++;我在C?_C_Performance_Optimization_Post Increment_Pre Increment - Fatal编程技术网

i++;和++;我在C?

i++;和++;我在C?,c,performance,optimization,post-increment,pre-increment,C,Performance,Optimization,Post Increment,Pre Increment,如果不使用结果值,i++和++i之间是否存在性能差异?执行摘要:否 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
之间是否存在性能差异?

执行摘要:否

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);

}
我们将编译它们,并获得生成的汇编程序:

$ 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

我的C有点生锈了,所以我提前道歉。就速度而言,我能理解结果。但是,我不明白这两个文件是如何产生相同的MD5散列的。也许for循环运行相同的程序集,但是下面的两行代码不会生成不同的程序集吗

myArray[i++] = "hello";
vs

第一个将值写入数组,然后递增i。然后,我将第二个增量写入数组。我不是汇编专家,但我不知道这两行不同的代码如何生成相同的可执行文件


只要我的两分钱。

在C中,如果结果未使用,编译器通常可以将它们优化为相同的


<>但是,在C++中,如果使用其他类型的提供自己的++操作符,前缀版本可能比后缀版本快。因此,如果不需要后缀语义,最好使用前缀运算符。

学习Scott Meyers的第6项:区分递增和递减操作的前缀和后缀形式

在对象方面,前缀版本总是优于后缀版本,尤其是在迭代器方面

如果你看一下运营商的呼叫模式,就会发现原因是什么

// Prefix
Integer& Integer::operator++()
{
    *this += 1;
    return *this;
}

// Postfix
const Integer Integer::operator++(int)
{
    Integer oldValue = *this;
    ++(*this);
    return oldValue;
}
看看这个例子,很容易看出前缀操作符如何总是比后缀更有效。因为在使用后缀时需要一个临时对象

这就是为什么当您看到使用迭代器的示例时,它们总是使用前缀版本


但正如您所指出的,对于int,实际上没有什么区别,因为编译器可以进行优化。

更好的答案是,
++i
有时会更快,但不会更慢

每个人似乎都认为
i
是一种常规的内置类型,例如
int
。在这种情况下,将没有可测量的差异

然而,如果
i
是复杂类型,那么您可能会发现一个可测量的差异。对于
i++
,在递增类之前,必须先复制一个类。根据副本中涉及的内容,它的速度确实可能会较慢,因为使用
++it
可以只返回最终值

Foo Foo::operator++()
{
  Foo oldFoo = *this; // copy existing value - could be slow
  // yadda yadda, do increment
  return oldFoo;
}
另一个区别是,使用
++i
可以选择返回引用而不是值。同样,根据制作对象副本所涉及的内容,这可能会更慢


一个真实的例子是迭代器的使用。复制迭代器不太可能成为应用程序中的瓶颈,但在结果不受影响的情况下,养成使用
++i
而不是
i++
的习惯仍然是一个很好的做法。

如果您担心微观优化,这里有一个额外的观察。递减循环“可能”比递增循环更有效(取决于指令集架构,如ARM),前提是:

循环将为以下各项提供一条指令:

  • 减量
    i
    ,设置CPU寄存器状态标志
  • 取决于CPU寄存器状态的条件分支(
    Z==0
  • 当然,这只在递减到零时有效

    还记得《ARM系统开发人员指南》。

    来自Andrew Koenig:

    首先,
    ++i
    i++
    更有效,这一点并不明显,至少在涉及整数变量时是如此

    以及:

    因此,我们应该问的问题不是这两个操作中哪一个更快,而是这两个操作中哪一个更准确地表达了您想要完成的任务。我认为,如果您没有使用表达式的值,则没有理由使用
    I++
    而不是
    ++I
    ,因为没有理由复制变量的值,增加变量,然后丢弃副本


    因此,如果不使用结果值,我将使用
    ++I
    。但这并不是因为它更有效:因为它正确地表达了我的意图

    请不要让“哪一个更快”成为使用哪一个的决定因素。很可能你永远不会那么在意,而且,程序员的阅读时间比机器时间要昂贵得多


    使用对阅读代码的人来说最有意义的方法。

    我总是喜欢预先递增,但是

    我想指出的是,即使在调用operator++函数的情况下,如果函数内联,编译器也能够优化掉临时函数。由于操作符++通常很短,并且通常在头中实现,因此它很可能是内联的

    因此,出于实际目的,这两种形式的性能可能没有太大区别。然而,我总是更喜欢pre-increment,因为直接表达我想说的内容似乎比依靠优化器来解决问题要好

    另外,给optmizer更少的操作可能意味着编译器运行得更快。

    @Mark 即使编译器被允许优化掉变量的(基于堆栈的)临时副本,而gcc(在最新版本中)正在这样做, 并不意味着所有的编译器都会这样做

    我只是测试了一下
    // Prefix
    Integer& Integer::operator++()
    {
        *this += 1;
        return *this;
    }
    
    // Postfix
    const Integer Integer::operator++(int)
    {
        Integer oldValue = *this;
        ++(*this);
        return oldValue;
    }
    
    Foo Foo::operator++()
    {
      Foo oldFoo = *this; // copy existing value - could be slow
      // yadda yadda, do increment
      return oldFoo;
    }
    
    for (i = 0; i < 100; i++)
    
    for (i = 100; i != 0; i--)
    
    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]