"++"和"+ = 1"运算符之间有什么区别?

E_l*_*ner 45 c++ integer loops increment auto-increment

在C++的循环中,我经常遇到要使用的情况,++或者+=1我无法区分它们.例如,如果我有一个整数

int num = 0;
Run Code Online (Sandbox Code Playgroud)

然后在循环中我做:

num ++;
Run Code Online (Sandbox Code Playgroud)

要么

num += 1;
Run Code Online (Sandbox Code Playgroud)

他们都增加了价值num,但他们的区别是什么?我怀疑num++可以比工作更快num+=1,但如何?这种差异是否足以被忽视?

Ale*_* C. 84

num += 1相当于++num.

所有这些表达式(num += 1,num++++num)增加值num的一个,但价值num++是值num之前它得到了增加.

插图:

int a = 0;
int b = a++; // now b == 0 and a == 1
int c = ++a; // now c == 2 and a == 2
int d = (a += 1); // now d == 3 and a == 3
Run Code Online (Sandbox Code Playgroud)

用你喜欢的任何东西.我喜欢++numnum += 1,因为它是短.

  • 缩短当然是一个重点,但IMO并不像"++ a"更为一致,并且保证能够有效地工作,而不仅仅是"int",而且也适用于任何类型的迭代器. (10认同)
  • @leftaroundabout:整数和迭代器彼此无关.我们不是在讨论这里的指针(并且`i + = 1`的正确概括将是`std :: advance(i,1)`),并且OP似乎还不足以使问题以这种方式复杂化.我坚持自己的观点:"i + = 1"和"++ i"对于整数(这就是所谓的)的唯一区别是化妆品. (5认同)
  • @AlexandreC.对于迭代器,没有`std :: advance(i,1)`可以工作但`++ i`不会工作的情况.我不认为`advance`是迭代器的'++ i`的正确推广.虽然这个答案+1. (2认同)
  • 旁注:在我的测试中,++i 可以在某些编译器(内存中的 GCC)上生成比 i++ 更高效的汇编,因为它可以避免创建额外的临时文件。 (2认同)

non*_*one 22

前缀后缀操作是考试问题的完美候选者.

a = 0;
b = a++;  // use the value and then increment --> a: 1, b: 0

a = 0;
b = ++a;  // increment and then use the value --> a: 1, b: 1
Run Code Online (Sandbox Code Playgroud)

+=操作及其姐妹-=是更通用的解决方案,主要用于不同的数字.有人甚至可能会说它们在使用时是多余的1.与1它们一起使用时,它们主要充当前缀操作.事实上,在我的机器上,它们生成相同的机器代码.您可以使用示例程序尝试此操作,例如:

void foo() {
    int a, b;
    a = 0;

    // use one of these four at a time
    b = a++;          // first case (different)
    b = ++a;          // second case
    b = (a += 1);     // third case
    b = (a = a + 1);  // fourth case
}

int main() {
    foo();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

并拆解gdb其中会给:

第一种情况(a++)(不同)

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    mov    -0x8(%rbp),%eax
   0x00000000004004c2 <+14>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c5 <+17>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

第二种情况(++a)

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c3 <+15>:    mov    -0x8(%rbp),%eax
   0x00000000004004c6 <+18>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq   
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

第三种情况(a += 1)

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c3 <+15>:    mov    -0x8(%rbp),%eax
   0x00000000004004c6 <+18>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq   
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

第四种情况(a = a + 1)

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c3 <+15>:    mov    -0x8(%rbp),%eax
   0x00000000004004c6 <+18>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq   
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,即使没有打开编译器优化,它们也会生成相同的机器代码,除了第一个具有s addl之后mov的情况.这意味着您应该使用任何您喜欢的用户,并让编译器人员完成剩下的工作.

最后,请注意表兄经营者*=/=没有后缀前缀对应物.


dre*_*zor 10

++前缀或后缀运算符改变变量值.

int a = 0;
int b = a++; // b is equal to 0, a is equal to 1
Run Code Online (Sandbox Code Playgroud)

或前缀:

int a = 0;
int b = ++a; // b = 1, a = 1
Run Code Online (Sandbox Code Playgroud)

如果像这样使用,它们是相同的:

int a = 0;
++a; // 1
a++; // 2
a += 1; // 3
Run Code Online (Sandbox Code Playgroud)

  • 要清楚,"a + = 1"也有一个返回值,但它是增量后的"a"的值. (2认同)
  • Re*`a + = 1`也有一个返回值*:`=`也是如此.`=`返回一个值,使得诸如`a = b = c = 0;'等语句有效. (2认同)
  • 它们没有返回值,它们是_expressions_并且评估为某些东西. (2认同)

Des*_*Ice 6

两个运算符都将n的值增加1.当您将运算符与赋值运算符一起使用时,它们之间存在差异.

例如:

第一种情况 - 后增量运算符

int n=5;
int new_var;

new_var=n++;

print("%d",new_var);
Run Code Online (Sandbox Code Playgroud)

输出= 5

第二个案例

int n=5;
n+=1;
new_var=n;
print("%d",new_var);
Run Code Online (Sandbox Code Playgroud)

输出= 6

这与预增量运算符的结果非常相似.

第二种情况使用预增量运算符

int n=5;

new_var=++n;
print("%d",new_var);
Run Code Online (Sandbox Code Playgroud)

输出= 6

  • 有两个++运算符,预增量(`++ n`)和后增量(`n ++`).你只看了后增量.尝试与pre-incrment进行比较.顺便说一句,C++中的推荐做法是,当两者中的任何一个都这样做时,更喜欢预增量而不是后增量. (2认同)
  • 编辑显示与预增量运算符的比较. (2认同)