Dlaczego C używa gwiazdki do wskaźników?
Po prostu - ponieważ zrobił to B.
Ponieważ pamięć jest tablicą liniową, możliwe jest interpretowanie wartości w komórce jako indeksu w tej tablicy, a BCPL dostarcza operator do tego celu. W oryginalnym języku został napisany rv
, a później !
, gdy B używa unarnego *
. Zatem jeśli p
komórka zawierająca indeks (lub adres) lub wskaźnik do innej komórki, *p
odnosi się do zawartości wskazanej komórki, albo jako wartość w wyrażeniu, albo jako cel zadania.
Od rozwoju języka C.
To jest to. W tym momencie pytanie jest tak nieciekawe, jak „dlaczego Python 3 używa .
metody do wywołania metody? Dlaczego nie ->
?” Cóż ... ponieważ Python 2 używa .
metody do wywołania metody.
Rzadko istnieje język z niczego. Ma wpływ i opiera się na czymś, co było wcześniej.
Dlaczego więc B nie użył !
do odstresowania wskaźnika, jak jego poprzednik BCPL?
Cóż, BCPL było trochę nieporadne. Zamiast &&
lub ||
użyto BCPL logand
i logor
. Stało się tak, ponieważ większość klawiatur nie ma ∧
ani ∨
klawiszy, a klucze nie są w rzeczywistości słowem NEQV
(patrz Podręcznik referencyjny BCPL ).
Wygląda na to, że B zostało częściowo zainspirowane raczej do zaostrzenia składni, zamiast mieć długie słowa dla wszystkich tych operatorów logicznych, które programiści robili dość często. I tak !
stało się dla dereferencji *
, aby !
można było je wykorzystać do logicznej negacji. Zauważ, że istnieje różnica między *
operatorem jednoargumentowym a *
operatorem binarnym (mnożenie).
A co z innymi opcjami ->
?
->
Została podjęta na cukier składniowej wokół derefrences polowych struct_pointer->field
, które jest(*struct_pointer).field
Inne opcje, takie jak <-
mogą tworzyć niejednoznaczne analizy. Na przykład:
foo <- bar
Czy to należy rozumieć jako:
(foo) <- (bar)
lub
(foo) < (-bar)
Utworzenie jednoargumentowego operatora, który składa się z binarnego operatora i innego jednoargumentowego operatora, może mieć problemy, ponieważ drugi jednoargumentowy operator może być prefiksem innego wyrażenia.
Co więcej, znowu ważne jest, aby często wpisywać rzeczy do minimum. Ja nienawidzę mieć napisać:
int main(int argc, char->-> argv, char->-> envp)
To również staje się trudne do odczytania.
Możliwe były inne postacie ( @
nie były używane, dopóki cel C nie przywłaszczył ich ). Chociaż znowu chodzi o sedno „zastosowań C, *
ponieważ B to zrobił”. Dlaczego B nie używał @
? Cóż, B nie użył wszystkich znaków. Nie było bpp
programu (porównaj cpp ), a inne znaki były dostępne w B (takie jak te, #
które były później używane przez cpp).
Jeśli mogę zaryzykować zgadnięcie, dlaczego - to z powodu tego, gdzie są klucze. Z instrukcji na temat B :
Aby ułatwić manipulowanie adresami, gdy wydaje się to wskazane, B udostępnia dwóch jednoargumentowych operatorów adresów *
i &
. &
jest operatorem adresu, podobnie &x
jak adres x
, zakładając, że ma jeden. *
jest operatorem pośrednim; *x
oznacza „użyj zawartości x jako adresu”.
Zauważ, że &
jest to shift-7 i *
shift-8. Ich bliskość mogła być dla programisty wskazówką, co robią ... ale to tylko przypuszczenie. Trzeba by zapytać Kena Thompsona, dlaczego dokonano takiego wyboru.
Więc masz to. C jest w ten sposób, ponieważ B był. B jest w ten sposób, ponieważ chciał zmienić z BCPL.
->
jest używany w języku C jako operator dereferencji - podczas uzyskiwania dostępu do pól w struct:,struct_pointer->field
co jest skrótem(*struct_pointer).field
.