繁体   English   中英

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

[英]In regards to for(), why use i++ rather than ++i?

也许对编译器进行优化后并不重要,但是在C / C ++中,我看到大多数人都会以以下形式进行for循环:

for (i = 0; i < arr.length; i++)

使用postfix ++完成增量。 我得到了两种形式之间的区别。 i ++返回i的当前值,但是在安静时将1加到i上。 ++ i首先将1加到i,然后返回新值(比i大1)。

我认为i ++需要做更多的工作,因为除了下一个值外,还需要存储上一个值:推*(&i)进行堆栈(或加载至寄存器); 递增*(&i)。 与++ i:增量*(&i); 然后根据需要使用*(&i)。

(根据CPU的设计,我知道“ Increment *(&i)”操作可能涉及寄存器加载。在这种情况下,i ++将需要另一个寄存器或堆栈压入。)

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


我倾向于相信azheglov:这是一种教学方法,由于我们大多数人都在Window或* nix系统上执行C / C ++,因此编译器的质量很高,没有人受到伤害。

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

不管使用哪个。 在某些极其陈旧的计算机上,以及在某些使用C ++的实例中, ++i效率更高,但是现代编译器不会存储结果(如果未存储)。 至于什么时候在for循环中使用后增量写法,我的K&R第二版副本使用第65页的i++ (我在翻阅时发现的第一个for循环)。

出于某种原因,即使i++ 创建了不必要的副本也在C i++变得更加惯用了。 (我认为这是通过K&R进行的,但是我在其他答案中也对此进行了辩论。)但是我认为C中没有性能差异,因为C仅用于内置函数,因此编译器可以优化复制操作。

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

至于原因,这是K&R在这个问题上必须说的:

布赖恩·克尼根(Brian Kernighan)

您将不得不问丹尼斯(可能在HOPL文件中 )。 我的内存很暗淡,它与pdp-11中的后递增操作有关,尽管除此之外我不知道,所以请不要引用我的话。

在c ++中,出于某些微妙的实现原因,迭代器的首选样式实际上是++ i。

丹尼斯·里奇

没什么特别的原因,它刚刚成为时尚。 产生的代码在PDP-11上相同,只是一个inc指令,没有自动递增。

HOPL纸

汤普森(Thompson)更进一步,发明了++和-运算符,它们递增或递减; 它们的前缀或后缀位置确定更改是在记录操作数的值之前还是之后进行。 它们不是B的最早版本,而是一路出现。 人们通常会猜测,它们是使用DEC PDP-11提供的自动递增和自动递减地址模式创建的,C和Unix最初在DEC PDP-11上流行。 从历史上讲这是不可能的,因为开发B时没有PDP-11。 但是,PDP-7确实具有一些“自动递增”存储单元,其特性是通过它们进行的间接存储引用增加了该单元。 汤普森(Thompson)可能建议使用此运算符。 使它们都带有前缀和后缀的概括是他自己的。 的确,自动递增单元并没有直接用于运算符的实现中,而创新的更大动力可能是他观察到++ x的翻译小于x = x + 1的翻译。

对于整数类型,当您不使用表达式的值时,两种形式应等效。 在具有更复杂类型的C ++世界中,这不再是正确的,而是保留在语言名称中。

我怀疑“ i ++”在早期变得更流行,因为那是原始K&R“ The C Programming Language”一书中使用的样式。 您必须问他们为什么选择了该变体。

因为一旦您开始使用“ ++ i”,人们就会感到困惑和好奇。 他们将停止在那里的日常工作,并开始使用Google搜索进行解释。 12分钟后,他们将进入堆栈溢出并创建这样的问题。 瞧,您的老板又花了10美元

比K&R回溯了一下,我看了一下它的前身: Kernighan的C教程 (〜1975年)。 这里最初的几个while示例使用++n 但是每个for循环都使用i++ 因此,回答您的问题:从一开始, i++几乎变得更加流行。

我认为随着C ++的创建,它变得更加流行,因为C ++允许您在非平凡的对象上调用++。

好的,我要详细说明一下:如果您调用i++并且i是一个非平凡的对象,那么在增量之前存储包含i值的副本将比使用指针或整数昂贵。

在某种程度上,它是惯用的C代码。 这只是通常的处理方式。 如果这是您最大的性能瓶颈,那么您可能正在解决一个独特的问题。

但是,查看我的《 K&R C编程语言》第一版,我在循环中发现i的第一个实例(第38页)确实使用++ i而不是i ++。

我的理论(为什么i ++更流行)是,当人们学习C(或C ++)时,他们最终将学习如下代码:

while( *p++ ) {
    ...
}

请注意,后缀形式在这里很重要(使用infix形式会创建一次性错误)。

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

添加:我上面写的内容确实适用于原始类型。 当用原始类型编码某些东西时,您倾向于快速地做事,并自然而然地做。 这是我需要附加到理论上的重要警告。

如果++是C ++类上的重载运算符(注释中可能提到Rich K.),那么您当然需要格外小心地编写涉及此类的循环,而不是自然而然地完成简单的事情。

对于选择后增量而不是前增量的副作用,我认为我的前任是正确的。

由于它的可辨识性,它很简单,就像您以相同的重复方式在for语句中启动所有三个表达式一样,这似乎是人脑所趋向的。

我加起来就是其他人告诉你的主要规则是:保持一致。 选择一种,除非有特殊情况,否则不要使用另一种。

如果循环太长,则需要在跳转到开头之前在高速缓存中重新加载该值以使其递增。 ++ i不需要的东西,没有缓存移动。

在C语言中,除前缀inc / dec外,所有导致变量具有新值的运算符都会修改左手变量 (i = 2,i + = 5等)。 因此,在可以互换++ i和i ++的情况下,许多人对i ++更加满意,因为运算符位于右侧,修改了左侧变量

请告诉我第一句话是否正确,我不是C语言专家。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM