Почему 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.
->
он используется на языке C в качестве оператора разыменования - при доступе к полям в struct:,struct_pointer->field
что сокращенно(*struct_pointer).field
.