2015-05-25 12 views
10

(Примечание.. Я не прошу об определениях преинкремента против постинкремента, или, как они используются в C/C++ Поэтому я не думаю, что это дубликат вопрос)Каковы исторические причины Языки C имеют предварительные приращения и пост-приращения?

Разработчики из C (Деннис Ричи и др.) создали приращения и сокращения операторов по очень веским причинам. Я не понимаю, почему они решили создать различие пре-инкрементов/декрементов?

Я считаю, что эти операторы были гораздо полезнее, когда C разрабатывался, чем сегодня. Большинство программистов на C/C++ используют одно или другое, а программисты из других языков находят различие сегодня странным и запутанным (NB: это основано исключительно на анекдотических доказательствах).

Почему они решили сделать это, и что изменилось в расчетах, что это различие сегодня не так полезно?

Для записи, разница между ними можно увидеть в C++ код:

int x = 3; 

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

даст в качестве выходного сигнала

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

[Разработка языка C (по Ritchie)] (http://cm.bell-labs.co/who/dmr/chist.html) содержит абзац об операторах инкрементации, а также постфикс/префикс, но не вдаваясь в подробности. – dyp

+2

Побочный эффект - это то, что полезно. –

+1

[Предупреждение о спекуляции] При программировании систем на C или C++ вы в конечном итоге пишете много кода. Все, что помогает вам оставаться кратким, хорошо. Операторы префикса и постфикса позволяют программистам тратить меньше места на переменную жонглирование. Я думаю, именно поэтому они добавили его. Я удивлен тем, что C не имеет оператора с переменными значениями. – Dai

ответ

10

Увеличение и уменьшение на 1 широко поддерживаются аппаратными средствами в время: один код операции и быстро. Это потому, что «увеличение на 1» и «уменьшение на 1» были очень распространенной операцией в коде (истинно по сей день).

Формы post и preecrement влияют только на место, где этот код операции вставлен в сгенерированный машинный код. Концептуально это имитирует «увеличение/уменьшение до или после с использованием результата». В одном операторе

i++; 

«до/после» понятие не используется (и поэтому он делает то же самое, как ++i;), но в

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

это. Это различие так же важно в наши дни, как и когда был разработан язык C (эта конкретная идиома была скопирована из ее предшественника с именем «B»).

От The Development of the C Language

Эта функция [ "` автоинкрементные»клетки памяти" PDP-7], вероятно, предложил такие операторы Томпсона [Кен Томпсон, который разработал "B", предшественник C]; обобщение, чтобы сделать их как префикс, так и постфикс, было его собственным. Действительно, ячейки с автоматическим инкрементом не использовались непосредственно в реализации операторов, и более сильной мотивацией для нововведения было, вероятно, его наблюдение, что перевод ++ x был меньше, чем у x = x + 1.

Благодаря @dyp для упоминания этого документа.

+6

Ritchie, разработка языка C: * «Люди часто догадываются, что они были созданы для использования режимов автоинкремента и автоматического уменьшения адреса DEC PDP-11, на котором C и Unix стали популярными. Это исторически невозможно, так как не было PDP-11, когда был разработан B ». * У PDP-7, похоже, есть некоторые функции, которые могли сыграть свою роль, хотя я не думаю, что из документа совершенно ясно, что они являются основной причиной существования как префикса, так и postfix '++'. – dyp

+0

@dyp: правда, может быть, я не верю, что они придумали это «из ничего». Команда «inc X» может существовать до PDP-11. – usr2564301

+0

Я пересмотрел свой комментарий. Производительность могла быть одним аспектом, но я не думаю, что коды операций могут показать всю картину. – dyp

0

PDP-11 имеет одну инструкцию, которая соответствует *p++, а другая для *--p (или, возможно, наоборот).

+0

См. [Развитие языка C (Ritchie)] (http://cm.bell-labs.co/who/dmr/chist.html). Эти операторы были в B, что было до PDP-11. – dyp

2

Чтобы получить ответ, выходящий за рамки спекуляций, скорее всего, вы должны спросить Денниса Ричи и других лично.

Добавление к ответу уже дал, я хотел бы добавить две возможные причины я придумал:

  • ленивости/сохранения пространства:

    вы могли бы сэкономить несколько нажатий клавиш/bytes во входном файле, используя соответствующую версию в конструкциях, таких как while(--i) против while(i--). (Обратите внимание на ГПМ сек ответ увидеть, почему и сделать разницу, если вы не видели его в первом запуске)

  • эстетику

    Из соображений симметрии, имеющих только один вариант либо заранее или postincrement/декремент может чувствовать, что что-то пропало.

EDIT: добавлено щадя несколько байт во входном файле в секции спекуляции обеспечения, в настоящее время предоставляет довольно хорошую «историческую» причину.

В любом случае главное в составлении списка приводило примеры возможных объяснений, которые не были слишком историческими, но все еще держат сегодня.

Конечно, я не уверен, но я думаю, что просить «историческую» причину, отличную от личного вкуса, исходит из предположения, которое не обязательно верно.

+3

К сожалению, чтобы спросить Денниса, вам понадобится доска Ouija - он скончался 4 года назад. –

+0

oops, я не знал, что ... – mikyra

+2

mikyra, рука в вашем крестине. Затем вы расскажете нам, что вы не знали о Леонарде Нимое :-) – paxdiablo

5

Когда вы отсчитывать от 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; 
} 

См code running at ideone.

+0

Спасибо, что разделили эту мудрость. Я добавил ссылку на ваш пост. Скорее всего, мое предположение, что разница между обоими версиями - это obvios, была неправильной, и в моем ответе она как-то переусердствовала. – mikyra

2

Для C

Давайте посмотрим на Kernighan & Ritchie оригинального обоснования (оригинал K & R страница 42 и 43):

Необычные аспекты в том, что ++ и - может быть использован либо как префикс, либо в качестве постфикса. (...) В контексте, где никакое значение не требуется (..), выберите префикс или постфикс по вкусу. Но htere - это ситуации, когда тот или иной специально призван.

текст продолжается с некоторыми примерами, которые используют приращение в индексе, с явной целью написания «более компактным» кодой. Поэтому причиной этих операторов является удобство более компактного кода.

В трех приведенных примерах (squeeze()strcat()) используется только постфикс в выражениях с использованием индексации. Авторы сравнивают код с более длинной версией, которая не использует встроенные приращения. Это подтверждает, что основное внимание уделяется компактности.

K & R выделить на стр. 102, использование этих операторов в сочетании с разыменованием указателя (например, *--p и *p--). Никаких дальнейших примеров не приводится, но опять же они дают понять, что преимущество - это компактность.

Для C++

Бьярне Страуструп хотел иметь совместимость с C, поэтому C++ унаследовал префикс и постфикс инкремента и декремента.

Но есть больше на нем: в своей книге «Конструкция и эволюция C++», Страуструп объясняет, что первоначально он планировал иметь только одну перегрузку и, суффикса и префикса, в определенных пользователем классов:

Несколько человек, в частности Брайан Керниган, отметили, что это ограничение было неестественным с точки зрения C и не позволило пользователям определить класс, который может использоваться в качестве замены обычного указателя .

Это привело к тому, что он нашел текущую разницу в сигнатуре, чтобы дифференцировать префикс и постфикс.

Кстати, без этих операторов C++ не будет C++, но C_plus_1 ;-)

1

Рассмотрим следующий цикл:

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

Вы не можете повторить этот цикл с пре- декремент без перемещения операции декремента вне конструкции for (...), и лучше всего иметь вашу инициализацию, взаимодействие и проверку всего в одном месте.

Гораздо большая проблема заключается в следующем: можно перегрузить операторы инкремента (все 4) для класса. Но тогда операторы критически разные: операторы сообщения обычно приводят к временной копии экземпляра класса, который, как и предоператоры, этого не делают. Это огромная разница в семантике.