Dlaczego C używa gwiazdki do wskaźników? [Zamknięte]

21

Właśnie uczę się o C.

Dziwne wydaje mi się to, że twórcy wybrali gwiazdkę ( *) jako symbol wskaźników zamiast symbolu, który faktycznie wygląda jak wskaźnik ( ->).

Biorąc pod uwagę, jak mylące mogą być dereferencje i wskaźniki funkcji, czy istnieje historyczny, a nawet praktyczny powód używania gwiazdki?

Noob Saibot
źródło
10
Zauważ, że ->jest używany w języku C jako operator dereferencji - podczas uzyskiwania dostępu do pól w struct:, struct_pointer->fieldco jest skrótem (*struct_pointer).field.
amon
@amon: Dotyczy to tylko structsdereferencji, co wydawało mi się dziwne. To symbol wskaźnika, prawda? Dlaczego nie ( <-) w przypadku dereferencji? Czy naprawdę jestem jedynym, który myśli w ten sposób?
Noob Saibot
1
Biorąc pod uwagę dwie doskonałe odpowiedzi w tym pytaniu, w tym jedną z odpowiedzią bezpośrednio od projektanta języka, trudno naprawdę uzasadnić zakończenie jako „oparte na opiniach”. Dlatego zostałem nominowany do ponownego otwarcia.
Jules
Styl IMHO Pascal jest lepszy. ^jest używany i można go traktować jak obróconą strzałkę i odczytywać jako „wskaż na”, to samo znaczenie, ->ale krótsze. ^integeroznacza „wskaźnik do liczby całkowitej” dla deklaracji typu i var^oznacza „pamięć varwskazuje na” dla dereferencji. Pozycja symbolu jest bardziej logiczna niż C podczas czytania od lewej do prawej, które zawsze umieszczane są po typie i przed nazwą zmiennej. Pascal używa również @do pobierania adresu, co jest lepsze niż &, ponieważ @varjest to „adres, pod którym znajduje się var”
phuclv 14.04.18

Odpowiedzi:

59

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 pkomórka zawierająca indeks (lub adres) lub wskaźnik do innej komórki, *podnosi 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 logandi 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 bppprogramu (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 &xjak adres x, zakładając, że ma jeden. *jest operatorem pośrednim; *xoznacza „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.

Społeczność
źródło
2
...niesamowite! To świetna odpowiedź, @MichaelT! Pokazałeś mi zarówno historyczne, jak i praktyczne powody, a nawet rzeczy, których nie do końca rozumiałem, ale mogłem przyjrzeć się im. Dziękuję Ci. +1
Noob Saibot
@NoobSaibot Wybór postaci nie jest aż tak dużym problemem, jak fakt, że operator jest operatorem przedpłacającym, a nie postpendowym. Wymaga to wielu dodatkowych parenów (choć pomaga cukier syntaktyczny -), co może prowadzić do głupich, ale irytujących błędów, nawet dla doświadczonego programisty C ++.
Trixie Wolf,
1
Możesz także wspomnieć, że C znalazł zastosowanie w prawie każdej postaci interpunkcyjnej Ascii. Nie było wielu części zamiennych. Myślę, że @byłaby to inna możliwość.
david.pfx
1
@ david.pfx Rozwinęłem to - chociaż to nie C dokonało tego wyboru ... to był B. I, cóż, zgadłem, dlaczego (bliskość klawiatury &i *). B również nie używał, #więc było wtedy kilka dodatkowych części ... jest też $.
1
@ david.pfx Samouczek B, który znalazłem, został napisany przez BW Kernighana. Niestety Dennisa Ritchie nie można już pytać (zmarł w październiku 11), podczas gdy Kernighan jest najwyraźniej profesorem w dziale CS w Princeton. Ken Thompson (inny twórca B) pracuje w Google ... Być może wystąpił problem z niektórymi klawiaturami (oznaczonymi literami C dla czegoś, co uważalibyśmy za zwykłe klawisze) sugerując, że nie wszystkie z nich były dostępne ( Nie jestem pewien, czy „@” było).
55

Student zapytał mnie, czy & i *zostały wybrane, ponieważ były one obok siebie na klawiaturze (coś, czego nigdy wcześniej nie zauważyłem wcześniej). Wiele googlingów doprowadziło mnie do dokumentacji B i BCPL i tego wątku. Jednak w ogóle nie mogłem znaleźć wiele. Wyglądało na to, że *w B było wiele powodów , ale nie mogłem znaleźć niczego &.

Dlatego zgodnie z sugestią @ MichaelT zapytałem Kena Thompsona:

Od: Ken Thompson <[email protected]>

w pobliżu na klawiaturze: nie.
c skopiowane z b więc & i * są tam takie same.
b dostałem * z wcześniejszych języków - asembler,
bcpl i myślę, że pl / 1.
myślę, że użyłem & ponieważ nazwa (ampersand)
brzmi jak „adres”. b został zaprojektowany do pracy z
teletypem modelu 33. (5-bitowy kod baud-o),
więc użycie symboli zostało ograniczone.

chmullig
źródło
19
+1 za skontaktowanie się z Kenem Thompsonem i zgłoszenie się tutaj.
stakx