Warum verwendet C das Sternchen für Zeiger? [geschlossen]

21

Ich lerne gerade etwas über C.

Ich finde es seltsam, dass die Ersteller das Sternchen ( *) als Symbol für Zeiger gewählt haben und nicht als Symbol, das tatsächlich wie ein Zeiger aussieht ( ->).

Wenn man bedenkt, wie verwirrend Dereferenzierungs- und Funktionszeiger sein können, gibt es einen historischen oder sogar praktischen Grund für die Verwendung des Sternchens?

Noob Saibot
quelle
10
Beachten Sie, ->dass in der Sprache C als Dereferenzierungsoperator verwendet wird - beim Zugriff auf Felder in einer struct : struct_pointer->field, die Abkürzung für (*struct_pointer).field.
amon
@amon: Es gilt nur structsfür die Dereferenzierung, was mir komisch erschien. Es ist ein Zeigersymbol, richtig? Warum nicht ( <-) zur Dereferenzierung? Bin ich wirklich der einzige, der so denkt?
Noob Saibot
1
Angesichts der beiden hervorragenden Antworten in dieser Frage, einschließlich einer Antwort direkt vom Sprachdesigner, ist es schwierig, den Abschluss wirklich als "meinungsbasiert" zu rechtfertigen. Ich habe daher zur Wiedereröffnung vorgeschlagen.
Jules
IMHO Pascal-Stil ist besser. ^wird verwendet und kann als gedrehter Pfeil interpretiert und als "point to" gelesen werden ->. ^integerbedeutet "Zeiger auf Ganzzahl" für die Typdeklaration und var^bedeutet "der Speicher varzeigt auf" für die Dereferenzierung. Die Symbolposition ist logischer als C beim Lesen von links nach rechts, wobei immer nach dem Typ und vor dem Variablennamen gesetzt wird. Pascal auch Anwendungen @für die Adresse unter, die als besser ist &, weil @var„die Adresse , an der var liegt“
phuclv

Antworten:

59

Warum verwendet C das Sternchen für Zeiger?

Einfach - weil B es tat.

Da der Speicher ein lineares Array ist, kann der Wert in einer Zelle als Index in diesem Array interpretiert werden, und BCPL stellt zu diesem Zweck einen Operator bereit. In der Originalsprache wurde es geschrieben rvund später !, während B das Unäre verwendet *. Wenn palso eine Zelle den Index (oder die Adresse) einer anderen Zelle enthält oder auf eine andere Zelle zeigt, *pbezieht sie sich entweder als Wert in einem Ausdruck oder als Ziel einer Zuweisung auf den Inhalt der Zelle, auf die verwiesen wird.

Aus der Entwicklung der C-Sprache

Das ist es. An dieser Stelle ist die Frage so uninteressant wie "Warum wird in Python 3 .eine Methode aufgerufen? Warum nicht ->?". Nun ... weil Python 2 verwendet ., um eine Methode aufzurufen.

Selten existiert eine Sprache aus dem Nichts. Es hat Einflüsse und basiert auf etwas, das vorher kam.


Warum hat B also nicht !wie sein Vorgänger BCPL einen Zeiger für die Dereferenzierung verwendet?

Nun, BCPL war ein bisschen wortreich. Anstelle von &&oder ||BCPL verwendet logandund logor. Dies lag daran, dass die meisten Tastaturen keine oder Tasten haben und nicht gleich dem Wort war NEQV(siehe BCPL-Referenzhandbuch ).

B scheint teilweise inspiriert worden zu sein, die Syntax zu verschärfen, anstatt lange Wörter für all diese logischen Operatoren zu haben, die Programmierer ziemlich häufig taten. Und so wurde !für die Dereferenzierung *, dass !für die logische Verneinung verwendet werden konnte. Beachten Sie, dass es einen Unterschied zwischen dem unären *und dem binären *Operator gibt (Multiplikation).


Wie sieht es mit anderen Optionen aus ->?

Das ->wurde für syntaktischen Zucker um Felddifferenzen genommen, struct_pointer->fielddas ist(*struct_pointer).field

Andere Optionen wie <-können zu mehrdeutigen Parsings führen. Beispielsweise:

 foo <- bar

Ist das zu lesen als:

(foo) <- (bar)

oder

(foo) < (-bar)

Es ist sehr wahrscheinlich, dass ein unärer Operator, der aus einem binären Operator und einem anderen unären Operator besteht, Probleme verursacht, da der zweite unäre Operator ein Präfix für einen anderen Ausdruck sein kann.

Darüber hinaus ist es wieder wichtig zu versuchen, die häufig getippten Dinge auf ein Minimum zu beschränken. Ich würde es hassen , schreiben zu müssen:

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

Dies wird auch schwer zu lesen.

Möglicherweise waren auch andere Zeichen möglich (die @wurden erst verwendet, nachdem sie von Ziel C übernommen wurden ). Dies geht jedoch wieder zum Kern von "C verwendet, *weil B es getan hat". Warum hat B nicht verwendet @? Nun, B hat nicht alle Zeichen verwendet. Es gab kein bppProgramm (vergleiche cpp ) und andere Zeichen waren in B verfügbar (wie sie #später von cpp verwendet wurden).

Wenn ich eine Vermutung wagen darf, warum - liegt es daran, wo sich die Schlüssel befinden. Aus einem Handbuch zu B :

Um die Manipulation von Adressen zu erleichtern, wenn es ratsam erscheint, stellt B zwei unäre Adressoperatoren zur Verfügung, *und &. &Ist der Adressoperator so &xist die Adresse von x, vorausgesetzt, es hat eine. *ist der Indirektionsoperator; *xbedeutet "benutze den Inhalt von x als Adresse."

Beachten Sie, dass &Shift-7 und *Shift-8 ist. Ihre Nähe zueinander mag für den Programmierer ein Hinweis darauf gewesen sein, was sie tun ... aber das ist nur eine Vermutung. Man müsste Ken Thompson fragen, warum diese Wahl getroffen wurde.


Also, da hast du es. C ist so, weil B war. B ist so, weil es ändern wollte, wie BCPL war.

Gemeinschaft
quelle
2
...genial! Das ist eine großartige Antwort, @MichaelT! Sie haben mir sowohl historische als auch praktische Gründe aufgezeigt, und sogar Dinge, die ich nicht ganz verstand, aber untersuchen konnte. Vielen Dank. +1
Noob Saibot
@NoobSaibot Die Wahl des Charakters ist nicht so wichtig wie die Tatsache, dass der Operator eher ein Präpend-Operator als ein Postpend-Operator ist. Dies erfordert viele zusätzliche Parens (obwohl der -> syntaktische Zucker hilft), was selbst für einen erfahrenen C ++ - Programmierer zu albernen, aber ärgerlichen Fehlern führen kann.
Trixie Wolf
1
Sie könnten auch erwähnen, dass C eine Verwendung für fast jedes ASCII-Interpunktionszeichen gefunden hat. Es gab nicht viele Ersatzteile. Ich denke, @wäre eine andere Möglichkeit gewesen.
david.pfx
1
@ david.pfx Ich habe das erweitert - obwohl es nicht C war , das diese Wahl getroffen hat ... es war B. Und nun, ich habe geraten , warum (Tastaturnähe von &und *). B hat es auch nicht benutzt, #also gab es ein paar mehr Ersatzteile ... es gibt auch $.
1
@ david.pfx Das B-Tutorial , das ich gefunden habe, wurde von BW Kernighan geschrieben. Leider kann Dennis Ritchie nicht mehr gefragt werden (er starb im Oktober '11), während Kernighan anscheinend noch Professor an der CS-Abteilung in Princeton ist. Ken Thompson (der andere Schöpfer von B) arbeitet bei Google ... Möglicherweise gab es auch Probleme mit einigen Tastaturen (angezeigt durch die Trigraphen für C für das, was wir als gemeinsame Tasten ansehen würden), was darauf hindeutet, dass nicht alle verfügbar waren ( Ich bin mir nicht sicher, ob '@' war).
55

Ich wurde von einem Studenten gefragt, ob &und ob *sie ausgewählt wurden, weil sie auf der Tastatur nebeneinander standen (etwas, das ich noch nie bemerkt hatte). Viel googeln führte mich zu B und BCPL Dokumentation und diesem Thread. Ich konnte jedoch nicht viel finden. Es schien, als gäbe es viele Gründe für *in B, aber ich konnte nichts dafür finden &.

Auf Vorschlag von @ MichaelT habe ich Ken Thompson gefragt:

Von: Ken Thompson <[email protected]>

in der Nähe auf der Tastatur: Nein.
c kopiert von b so & und * sind dort gleich. Ich
habe * aus früheren Sprachen - einige Assembler,
bcpl und ich denke pl / 1.
Ich denke, dass ich & verwendet habe, weil der Name (kaufmännisches Und)
wie "Adresse" klingt. b wurde für den Betrieb mit
einem Teletyp Modell 33 entwickelt. (5-Bit-Baud-O-Code),
so dass die Verwendung von Symbolen eingeschränkt war.

chmullig
quelle
19
+1 für die Kontaktaufnahme mit Ken Thompson und die Rückmeldung hier.
Stakx