Почему C использует звездочку для указателей? [закрыто]

21

Я только сейчас узнаю о C.

Я нахожу странным, что создатели выбрали звездочку ( *) в качестве символа для указателей, а не символ, который на самом деле выглядит как указатель ( ->).

Учитывая, насколько запутанными могут быть разыменование и указатели на функции, есть ли историческая или даже практическая причина использования звездочки?

Нуб сайбот
источник
10
Обратите внимание, что ->он используется на языке C в качестве оператора разыменования - при доступе к полям в struct:, struct_pointer->fieldчто сокращенно (*struct_pointer).field.
Амон
@amon: Это касается только structsразыменования, что показалось мне странным. Это символ указателя, верно? Почему не ( <-) для разыменования? Я действительно единственный, кто так думает?
Нуб Сайбот
1
Учитывая два превосходных ответа в этом вопросе, в том числе один с ответом непосредственно от дизайнера языка, трудно действительно оправдать закрытие как «основанное на мнении». Поэтому я номинирован на повторное открытие.
Жюль
ИМХО стиль Паскаля лучше. ^используется и может восприниматься как вращающаяся стрелка и читаться как «указывает на», то же самое значение, ->но короче. ^integerозначает «указатель на целое число» для объявления типа и var^означает «память varуказывает на» для разыменования. Положение символа более логично, чем C при чтении слева направо, которое всегда ставится после типа и перед именем переменной. Паскаль также использует @для получения адреса, который лучше, чем &, потому что @varэто «адрес, по которому находится var»
phuclv

Ответы:

59

Почему C использует звездочку для указателей?

Просто - потому что Б сделал.

Поскольку память является линейным массивом, можно интерпретировать значение в ячейке как индекс в этом массиве, и BCPL предоставляет для этого оператор. На языке оригинала оно было написано rv, а позже !, в то время как B использует одинарное *. Таким образом, если pячейка содержит индекс (или адрес) или указатель на другую ячейку, *pссылается на содержимое указанной ячейки, либо в качестве значения в выражении, либо в качестве цели назначения.

Из развития языка Си

Это оно. На данный момент вопрос столь же неинтересен, как «почему Python 3 использует .для вызова метода? Почему нет ->?» Хорошо ... потому что Python 2 использует .для вызова метода.

Редко язык существует из ничего. Это имеет влияние и основано на чем-то, что было раньше.


Итак, почему B не использовал !разыменование указателя, как его предшественник BCPL?

Ну, BCPL был немного многословным. Вместо &&или ||BCPL используется logandи logor. Это было связано с тем, что большинство клавиатур не имели или не были равны клавишам на самом деле NEQV(см . Справочное руководство BCPL ).

Кажется, что B был частично вдохновлен на ужесточение синтаксиса, а не на длинные слова для всех этих логических операторов, которые программисты делали довольно часто. И таким образом !для разыменования стало *так, что !можно было бы использовать для логического отрицания. Обратите внимание, что есть разница между унарным *оператором и бинарным *оператором (умножение).


Ну, а как насчет других вариантов ->?

->Было принято для синтаксического сахара вокруг поля derefrences struct_pointer->fieldкоторый(*struct_pointer).field

Другие варианты вроде <-могут создать неоднозначные парсинги. Например:

 foo <- bar

Это должно быть прочитано как:

(foo) <- (bar)

или

(foo) < (-bar)

Создание унарного оператора, состоящего из бинарного оператора и другого унарного оператора, вполне может иметь проблемы, поскольку второй унарный оператор может быть префиксом для другого выражения.

Кроме того, снова важно постараться свести к минимуму количество набираемых вещей. Я бы не хотел писать:

int main(int argc, char->-> argv, char->-> envp)

Это также становится трудно читать.

Другие символы могли быть возможными (они @не использовались, пока Objective C не присвоил их ). Хотя опять же, это относится к сути «C использует, *потому что B сделал». Почему B не использовал @? Ну, Б не использовал всех персонажей. Не было никакой bppпрограммы (сравните cpp ), и другие символы были доступны в B (например, #которые позже использовались cpp).

Если я могу рискнуть предположить, почему - это из-за того, где ключи. Из руководства по B :

Чтобы облегчить манипулирование адресами, когда это кажется целесообразным, B предоставляет два оператора унарных адресов, *и &. &является оператором адреса, так же &xкак и адрес x, при условии, что он есть. *является оператором косвенности; *xозначает «использовать содержимое х в качестве адреса».

Обратите внимание, что &это shift-7 и *shift-8. Их близость друг к другу, возможно, была подсказкой программисту о том, что они делают ... но это только предположение. Можно было бы спросить Кена Томпсона о том, почему был сделан этот выбор.


Итак, вот оно. С так, потому что Б было. В это так, потому что он хотел изменить то, как был BCPL.

Сообщество
источник
2
...классно! Это отличный ответ, @MichaelT! Вы показали мне как исторические, так и практические причины, и даже вещи, которые я не совсем понял, но мог рассмотреть. Спасибо. +1
Noob Saibot
@NoobSaibot Выбор символа не так важен, как тот факт, что оператор является оператором prepend, а не postpend. Это требует большого количества дополнительных символов (хотя синтаксический сахар -> помогает), которые могут привести к глупым, но неприятным ошибкам даже для опытного программиста C ++.
Трикси Вольф
1
Вы также можете упомянуть, что C нашел применение почти для каждого символа пунктуации Ascii. Там не было много запчастей. Я думаю, @была бы другая возможность.
david.pfx
1
@ david.pfx Я подробно остановился на этом - хотя не C сделал такой выбор ... это был B. И, ну, я догадался, почему (близость клавиатуры &и *). Б тоже не пользовался, #поэтому вокруг было еще несколько запчастей ... также $.
1
@ david.pfx Учебник B, который я нашел, был написан BW Kernighan. К сожалению, Деннис Ритчи больше не может быть запрошен (он скончался в октябре 11 года), в то время как Керниган, по-видимому, все еще является профессором кафедры CS в Принстоне. Кен Томпсон (другой создатель B) работает в Google ... Возможно, также были проблемы с некоторыми клавиатурами (обозначенными триграфами для C для того, что мы бы назвали общими клавишами), предполагая, что не все из них были доступны ( Я не уверен, был ли '@').
55

Я спросил студент , если &и *были выбраны потому , что они были рядом друг с другом на клавиатуре (что - то я никогда раньше не замечал). Много гуглинга привело меня к документации B и BCPL и этой теме. Тем не менее, я не мог найти много вообще. Казалось, что *в B было много причин , но я ничего не мог найти &.

Поэтому, следуя предложению @ MichaelT, я спросил Кена Томпсона:

От: Кен Томпсон <ken@google.com>

рядом на клавиатуре: нет.
c скопированы из b, поэтому & и * там же.
b получил * от более ранних языков - немного ассемблера,
bcpl и я думаю, что pl / 1.
Я думаю, что я использовал & потому что имя (амперсанд)
звучит как «адрес». b был разработан для работы с
телетайпом модели 33 телетайпа. (5-битный код в бодах),
поэтому использование символов было ограничено.

chmullig
источник
19
+1 за обращение к Кену Томпсону и сообщение здесь.
Stakx