我正在通过K& R工作,现在正在练习1-16。我发现到目前为止,书中只使用了预增量。
大多数其他教程书籍和我见过的源代码往往倾向于后增量,除非有明显的影响,例如while循环等。
这是K& R的风格或技术考虑因素吗?或者我只需要进一步完成本书以获得我的答案?!
答案 0 :(得分:9)
大约1000万年前,在优化编译器之前,这曾经很重要*。它真的不再存在了。理由是,为了以天真的方式实现后增量,需要额外的store
操作。编译器大多数都没有这样实现它,所以只是更喜欢在给定上下文的情况下使用哪种样式更有意义并且信任编译器做正确的事情。
* JimBalter正确指出这是永远一个问题,我不应该建议它曾经可能有问题。
答案 1 :(得分:5)
这有几个方面。
<强>语义强>
预增量(减量)和后增量(减量)的语义是不同的。前者在使用该值之前递增一个值,而后者在使用后递增一个值。例如
unsigned i;
for (i=0; i<10; i++ /* ++i */ ) { }
在这种情况下,无论是使用前增量还是后增量都无关紧要。这让我想到了第二个方面:
<强>上下文强>
有时使用前增量还是后增量都很重要,这取决于使用的上下文。请考虑以下示例:
char *p = "some string";
unsigned len = 0;
// test 1
while ('\0' != *p++) { len++; }
// test 2 (assumes that p points to a non-empty string)
while ('\0' != *++p) { ++len; }
test 1
的结果是字符串的长度,test 2
的结果是字符串的长度减去1。因为增量值p
用作表达式的一部分,所以在增量发生时重要:在表达式中使用p
之后(测试1),或者在使用之前(测试2)。由于len
未用作表达式的一部分,因此无论是使用前置增量还是后置增量,都无关紧要。
这让我想到了第三个方面。
<强>实施强>
为了实现后增量,必须存储p
的值以供以后使用以增加它,这会为临时值占用额外的存储空间。预增量不需要临时存储空间。但是,如果增量值不用作表达式的一部分,那么现代优化编译器能够为前后增量生成相同的代码,其中需要临时值来评估该表达式。
这让我想到了第四个方面(在上一段中略有暗示),但这与C ++有关。
<强>性能强>
在C ++中,递减和递增运算符可以重载(link)以处理复杂类型,而STL(link)确实大量使用它来实现迭代器(link )为其容器类型。在这种情况下,像
这样的值set::iterator it;
可能是一个相当复杂的事情,而不仅仅是一个简单的状态(即它不仅仅是一个原始整数)。在这种情况下,使用预增量++it
确实与后增量it++
产生差异,因为不需要存储临时值,就像发布所需的那样-increment如果在表达式中使用(请参阅上下文)。这可以节省一些运行时开销。
答案 2 :(得分:1)
我会说(即使后增量运算符由于后缀运算符的优先级较高而在标准中排在第一位),预增量是增加对象值的自然方式,因此如果使用它是一个很好的理由。你唯一想要的是增加一个对象的值,
(++E)
相当于(E+=1)
,但不是(E++)