关于for(),为什么使用i ++而不是++ i?

Ric*_*h K 10 php c c++ java

也许它在优化后对编译器无关紧要,但在C/C++中,我看到大多数人以下列形式制作for循环:

for (i = 0; i < arr.length; i++)
Run Code Online (Sandbox Code Playgroud)

使用post fix ++完成递增的地方.我得到了两种形式之间的区别.i ++返回i的当前值,但是在安静时将i加1.++我首先向i添加1,并返回新值(比我多1).

我认为i ++需要更多的工作,因为除了下一个值之外还需要存储先前的值:Push*(&i)to stack(或load to register); 增量*(&i).Versus ++ i:增量*(&i); 然后根据需要使用*(&i).

(我认为"递增*(&i)"操作可能涉及寄存器加载,具体取决于CPU设计.在这种情况下,i ++需要另一个寄存器或堆栈推送.)

无论如何,在什么时候,以及为什么,i ++变得更时尚?


我倾向于相信azheglov:这是一个教育学的东西,因为我们大多数人在Window或*nix系统上进行C/C++,编译器质量很高,没有人受伤.

如果您使用的是低质量编译器或解释环境,则可能需要对此敏感.当然,如果你正在进行高级C++或设备驱动程序或嵌入式工作,希望你已经足够经验丰富,这根本不是什么大问题.(狗是否具有佛性?谁真的需要知道?)

nmi*_*els 10

你使用哪个并不重要.在一些极其过时的机器上,在某些情况下使用C++,++i效率更高,但现代编译器如果没有存储则不会存储结果.至于什么时候它开始流行到for循环中,我的K&R第二版副本使用i++在第65页(for我在翻阅时发现的第一个循环.)


sbi*_*sbi 5

出于某种原因,在C 语言中i++变得更加惯用,即使它创造了一个不必要的副本.(我认为这是通过K&R,但我认为这在其他答案中存在争议.)但我不认为C中存在性能差异,它只用于内置函数,编译器可以优化复制操作.

但是,它确实在C++中有所不同,其中i可能是一个operator++()重载的用户定义类型.编译器可能无法断言复制操作没有可见的副作用,因此可能无法消除它.

  • 如果变量'i'是易失性的,则声明"i;" 必须生成代码.在简单地将所有内容视为易失性的简单编译器上,语句"i;" 仍然会生成代码.注意,如果"i"是易失性的,则语句"a = i ++;" 和"a = ++ i;" 两者都要求只读一次"i"; 在大多数体系结构中,都不能使用直接的就地增量. (5认同)
  • @R ..:我不确定你在砸什么.`i ++`的结果是增量前的`i`的值.为了返回该结果,必须在某处复制"i".(这是否可以在硬件中完成并不重要.结果仍然必须存储在某处.)如果表达式的结果被丢弃,编译器可能会消除此复制.如果`i`是`int`,我无法想象编译器不会这样做. (3认同)
  • 它**不会"创建一个不必要的副本.你正在将C++思维应用于C,这根本就不正确.没有副作用的表达式评估中没有"复制".你期望`i ``接受任何时间或生成任何代码?如果没有,为什么要`i ++;`比`++ i;`需要更多时间或生成更多代码? (2认同)
  • @R.:在我使用的嵌入式系统编译器中,"volatile"强制执行内存读取一次,如果'volatile'变量链接到I/O的地址,这种行为通常是绝对必要的港口.正如我一般不喜欢这样的设计,在许多I/O设备上,读取"做事".例如,在许多UARTS上,如果数据字节可用,则读取将检索数据并将其从队列中删除.如果不保证每次读取都不能保证在C中编写这样的设备代码是不可能的.也许是一个实现细节,但是一个常见的细节. (2认同)

azh*_*lov 1

我的理论(为什么 i++ 更流行)是,当人们学习 C(或 C++)时,他们最终会学会像这样编写迭代代码:

while( *p++ ) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,后修复形式在这里很重要(使用中缀形式会产生一次性的错误)。

当需要编写一个for循环时,++iori++并不重要,使用后缀形式可能会感觉更自然。

添加:我上面写的内容确实适用于原始类型。当使用原始类型编写代码时,您往往会快速做事并自然而然地做事。这是我需要对我的理论附加的重要警告。

如果++是 C++ 类上的重载运算符(Rich K. 在注释中建议的可能性),那么您当然需要极其小心地编码涉及此类类的循环,而不是做自然而然的简单事情。