简体   繁体   English

C语言有预增量和后增量的历史原因是什么?

[英]What are the historical reasons C languages have pre-increments and post-increments?

(Note: I am not asking about the definitions of pre-increment vs. post-increment, or how they are used in C/C++. Therefore, I do not think this is a duplicate question.) (注意:我不是在询问预增量与后增量的定义,或者它们在C / C ++中的使用方式。因此,我不认为这是一个重复的问题。)

Developers of C (Dennis Ritchie et al) created increment and decrement operators for very good reasons. C的开发人员(Dennis Ritchie等人)出于很好的理由创建了增量和减量运算符。 What I don't understand is why they decided to create the distinction of pre- vs post- increments/decrements? 我不明白为什么他们决定创造前后增量/减量的区别?

My sense is that these operators were far more useful when C was being developed than today. 我的感觉是,当C开发时,这些运算符比今天更有用。 Most C/C++ programmers use one or the other, and programmers from other languages find the distinction today bizarre and confusing (NB: this is based solely on anecdotal evidence). 大多数C / C ++程序员使用其中一种,而来自其他语言的程序员今天发现这种区别奇怪且令人困惑(注意:这完全基于轶事证据)。

Why did they decide to do this, and what has changed in computation that this distinction isn't so useful today? 他们为什么决定这样做,以及计算上发生了什么变化,这种区别今天没那么有用?

For the record, the difference between the two can be seen in C++ code: 为了记录,可以在C ++代码中看到两者之间的差异:

int x = 3;

cout << "x = 3; x++ == " << x++ << endl;
cout << "++x == " << ++x << endl;
cout << "x-- == " << x-- << endl;
cout << "--x == " << --x << endl;

will give as an output 将作为输出

x++ == 3
++x == 5
x-- == 5
--x == 3

Incrementing and decrementing by 1 were widely supported in hardware at the time: a single opcode, and fast . 当时硬件广泛支持递增和递减1:单个操作码,并且速度快 This because "incrementing by 1" and "decrementing by 1" were a very common operation in code (true to this day). 这是因为“递增1”和“递减1”是代码中非常常见的操作(直到今天)。

The post- and predecrement forms only affected the place where this opcode got inserted in the generated machine code. post和precrement表单仅影响在生成的机器代码中插入此操作码的位置。 Conceptually, this mimics "increase/decrease before or after using the result". 从概念上讲,这模仿了“ 使用结果之前之后增加/减少”。 In a single statement 在一个声明中

i++;

the 'before/after' concept is not used (and so it does the same as ++i; ), but in 没有使用'之前/之后'概念(因此它与++i;相同++i; ),但是

printf ("%d", ++i);

it is. 它是。 That distinction is as important nowadays as it was when the language C was designed (this particular idiom was copied from its precursor named "B"). 现在,这种区别与设计语言C时的区别同样重要(这个特定的习语是从其名为“B”的前体复制而来的)。

From The Development of the C Language C语言的发展谈起

This feature [PDP-7's "`auto-increment' memory cells"] probably suggested such operators to Thompson [Ken Thompson, who designed "B", the precursor of C]; 这个特征[PDP-7的“自动增量”存储单元“]可能会向Thompson [Ken Thompson,他设计的”B“,C的前身)建议这样的操作员。 the generalization to make them both prefix and postfix was his own. 使它们成为前缀和后缀的概括是他自己的。 Indeed, the auto-increment cells were not used directly in implementation of the operators, and a stronger motivation for the innovation was probably his observation that the translation of ++x was smaller than that of x=x+1. 实际上,自动增量单元并没有直接用于运算符的实现,并且创新的更强烈动机可能是他观察到++ x的翻译小于x = x + 1的翻译。

Thanks to @dyp for mentioning this document. 感谢@dyp提及此文档。

When you count down from n it is very important whether is pre-decrement or post-decrement 当你从n倒数时,无论是预先减量还是后减量都是非常重要的

#include <stdio.h>
void foopre(int n) {
    printf("pre");
    while (--n) printf(" %d", n);
    puts("");
}
void foopost(int n) {
    printf("post");
    while (n--) printf(" %d", n);
    puts("");
}
int main(void) {
    foopre(5);
    foopost(5);
    return 0;
}

See the code running at ideone . 查看在ideone上运行代码

To get an answer that goes beyond speculation, most probably you have to ask Dennis Ritchie et al personally. 为了得到超出猜测的答案,很可能你不得不亲自询问Dennis Ritchie等人。

Adding to the answer already given, I'd like to add two possible reasons I came up with: 添加到已经给出的答案,我想补充两个可能的原因:

  • lazyness / conserving space: 懒惰/节约空间:

    you might be able to save a few keystrokes / bytes in the input file using the appropriate version in constructs like while(--i) vs. while(i--) . 您可以在输入文件中使用适当的版本保存一些击键/字节,例如while(--i) vs while(i--) (take a look at pmg s answer to see, why both make a difference, if you didn't see it in the first run) (看看pmg的答案,看看,为什么两者都有所不同,如果你在第一次运行中没有看到它)

  • esthetics 美学

    For reasons of symmetry having just one version either pre- or postincrement / decrement might feel like missing something. 出于对称性的原因,只有一个版本的前后增量/减量可能会让人觉得缺少某些东西。

EDIT: added sparing a few bytes in the input file in the speculation section providing, now providing a pretty nice "historic" reason as well. 编辑:在推测部分提供的输入文件中添加了少量字节,现在提供了一个非常好的“历史”原因。

Anyways the main point in putting together the list was giving examples of possible explanations not being too historic, but still holding today. 无论如何,整理清单的主要观点是提供可能的解释的例子,这些解释不是太历史,但仍然在今天举行。

Of course I am not sure, but I think asking for a "historic" reason other than personal taste is starting from a presumtion not neccesarily true. 当然我不确定,但我认为除了个人品味之外,要求一个“历史性”的理由是从一个不必要的假设开始。

For C 对于C.

Let's look at Kernighan & Ritchie original justification (original K&R page 42 and 43): 让我们来看看Kernighan&Ritchie的原始理由(原始K&R第42页和第43页):

The unusual aspects is that ++ and -- may be used either as prefix or as postfix. 不寻常的方面是++和 - 可以用作前缀或后缀。 (...) In the context where no value is wanted (..) choose prefix or postfix according to taste. (...)在没有值的情况下(..)根据品味选择前缀或后缀。 But htere are situations where one or the other is specifically called for. 但是htere是特别要求其中一个或另一个的情况。

The text continues with some examples that use increments within index, with the explicit goal of writing " more compact " code. 本文继续介绍一些在索引中使用增量的示例,其明确目标是编写“ 更紧凑 ”的代码。 So the reason behind these operators is convenience of more compact code. 因此,这些运算符背后的原因是更紧凑的代码的便利性。

The three examples given ( squeeze() , getline() and strcat() ) use only postfix within expressions using indexing. 给出的三个示例( squeeze()getline()strcat() )仅使用索引在表达式中使用postfix。 The authors compare the code with a longer version that doesn't use embedded increments. 作者将代码与不使用嵌入式增量的较长版本进行比较。 This confirms that focus is on compactness. 这证实了重点是紧凑性。

K&R highlight on page 102, the use of these operators in combination with pointer dereferencing (eg *--p and *p-- ). 第10页的K&R重点介绍了这些运算符与指针解除引用(例如*--p*p-- )的结合使用。 No further example is given, but again, they make clear that the benefit is compactness. 没有给出进一步的例子,但同样,他们明确表示这种好处是紧凑的。

For C++ 对于C ++

Bjarne Stroustrup wanted to have C compatibility, so C++ inherited prefix and postfix increment and decrement. Bjarne Stroustrup希望具有C兼容性,因此C ++继承了前缀和后缀增量和减量。

But there's more on it: in his book " The design and evolution of C++ ", Stroustrup explains that initially, he planned have only one overload for both, postfix and prefix, in user defined classes: 但是还有更多内容:在他的“ C ++的设计和演变 ”一书中,Stroustrup解释说,最初,他计划在用户定义的类中只有一个重载,后缀和前缀:

Several people, notably Brian Kernighan, pointed out that this restriction was unnatural from a C perspective and prevented users from defining a class that could be used as replacement for an ordinary pointer. 有几个人,特别是Brian Kernighan,指出这种限制从C角度看是不自然的,并阻止用户定义一个可以用作普通指针替换的类。

Which caused him to find the current signature difference to differentiate prefix and postfix. 这导致他找到当前的签名差异来区分前缀和后缀。

By the way, without these operators C++ would not be C++ but C_plus_1 ;-) 顺便说一下,没有这些运算符,C ++就不会是C ++而是C_plus_1 ;-)

Consider the following loop: 考虑以下循环:

for(uint i=5; i-- > 0;)
{
    //do something with i,
    // e.g. call a function that _requires_ an unsigned parameter.
}

You can't replicate this loop with a pre-decrement operation without moving the decrement operation outside of the for(...) construct, and it's just better to have your initialization, interation and check all in one place. 您不能使用预递减操作复制此循环,而无需在for(...)构造之外移动递减操作,并且最好在一个位置进行初始化,交互和检查。

A much larger issue is this: one can over-load the increment operators (all 4) for a class. 一个更大的问题是:一个可以为一个类重载增量运算符(全部4个)。 But then the operators are critically different: the post operators usually result in a temporary copy of the class instance being made, where as the pre-operators do not. 但是后来运算符严重不同:后期运算符通常会导致正在创建的类实例的临时副本,而前运算符则不会。 That is a huge difference in semantics. 这在语义上是一个巨大的差异。

PDP-11有一条对应*p++指令,另一条对应*--p (或者可能反过来)。

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

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