c++ - 进一步了解 i++ 和 i=i+1

标签 c++ c assembly optimization post-increment

我想知道这两种增量形式之间是否存在差异。一些 links说 i++ 比 i=i+1 快;

作为我的观察者之一,对于汇编代码也是一样的。请检查图像,其中 i++ 和 i=i+1 的汇编代码相同 - enter image description here

还有一个link这表示以前增量运算符比加法和赋值更快是正确的,但现在编译器优化 i++ 和 i=i+1 相同。

是否有任何官方文件/文件可供我们引用以确认什么是完全正确的? (我通常会在 stackoverflow 上获得一个人的信用和接受的答案数量。在我提供的链接上找不到任何这样的东西)。

最佳答案

实际上,如果您使用 C++,最好习惯于编写 ++i。原因很简单:i++ 需要一个拷贝。

a = ++i; // a is set to the result of i+1
a = i++; // make a copy of i, compute i+1, save the copy of i in a

如果不进行优化,汇编代码将如下所示:

a = ++i;                            a = i++;

MOV eax, (i)                        MOV eax, (i)
                                    PUSH eax
ADD eax, 1                          ADD eax, 1
MOV (i), eax                        MOV (i), eax
                                    POP eax
MOV (a), eax                        MOV (a), eax

现在,通过优化,结果在 C 中是相同的,其中 ++ 运算符仅适用于整数和指针。

++-- 在那里是因为大多数处理器在写C的时间。因此,如果您要使用索引寄存器,则将应用这些说明:

char a[256];
...init 'a' in some way...
int sum =0;
for(int i = 0; i < 100; ++i)
{
    sum += a[i];
}

这可以用一个简单的 INC 来完成,如 (6502) 所示:

    LDA #00
    LDY #00
LOOP:
    CLC
    ADC ($80),Y
    INY              <-- ++i or i++
    CPY #100
    BCC LOOP

请注意,在 C 中,我们有另一种表示法来递增变量:

i += 1;

如果您需要将寄存器递增超过 1,这很实用:

i += 3;

或者每次加倍寄存器:

i += i;   // (equivalent to  i *= 2;  or  i <<= 1;  in C++)

问题:为什么 INCDEC 不与所有 80x86 一起使用?

曾经有一段时间 ADD reg, 1SUB reg, 1 指令比 INC reg 快DEC 注册。在过去,它更快,因为指令更小而且我们没有缓存(或很少)。今天,这两种指令可能大致相同。

根据下面的评论,“缓慢”的一个原因是 FLAGS 寄存器:

Intel Optimization Reference, section 3.5.1.1 Use of the INC and DEC Instructions

从另一个更新的评论来看,该英特尔文档中提到的缓慢问题似乎已在较新的处理器中得到修复。因此,如果事先知道,使用或不使用这些指令应取决于目标处理器。


正如 phresnel 在评论中指出的那样,i++++i 之间的区别对于很多人来说可能并不明确。对于整数,优化确实微不足道,即使使用 -O0 也肯定会发生。然而,在 C++ 中,情况就不同了。有一个带有两个增量运算符的类清楚地表明 i++ 需要一个拷贝(即使 data_ 只是一个整数,尽管在那种情况下你也可以这样做:return data_++——它仍然需要一个隐藏得很好的拷贝!):

class A
{
public:
    A& operator ++ () // ++i -- no copy
    {
        ...apply the ++ operation to 'data_'...
        return *this;    // return a reference to this
    }

    A  operator ++ (int) // i++ -- needs a temporary copy
    {
        // remember that the 'int' is totally ignored in the function,
        // its only purpose is to distinguish '++i' from 'i++'

        A copy = *this;    // here we need a copy
        ++*this;
        return copy;       // and here we return said copy
    }

private:
    some_type_t   data_;
};

请注意,现代 C++ 编译器不会在 i++ 函数中创建两个拷贝,因为返回值可以在不需要额外拷贝的情况下进行优化。

如果按照 Is there a performance difference between i++ and ++i in C++? 中的描述使用 i++,这两种情况之间的差异可以明显地显示为更慢(phresnel 提到的链接)

关于c++ - 进一步了解 i++ 和 i=i+1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26199576/

相关文章:

c++ - 如何在 cin.clear() 和 cin.ignore() 之后将光标移动到文本输出的末尾?

c - 在 Dev-c++ 和 gcc 4.8.2 中编译时,同一程序获得不同的输出

assembly - 从另一个汇编文件调用汇编过程?

c++ - 尽管包含 <typeinfo> ,但 Clang 拒绝 type_info 为不完整

c++ - 类型定义数组与在 C++ 中使用结构

c - 如何打印偶数正方形的表格?

linux - 创建一个 ELF 文件,其中 .text 部分之后的部分与 .text 部分非常远

assembly - 错误 1 ​​错误 A1000 : cannot open file :\masm32\includes\masm32rt. Inc

c++ - 调用没有类实例的 c++ 类方法?

c - Arduino Pro 迷你启动画面