Perché C usa l'asterisco per i puntatori?
Semplicemente perché B lo ha fatto.
Poiché la memoria è un array lineare, è possibile interpretare il valore in una cella come un indice in questo array e BCPL fornisce un operatore per questo scopo. Nella lingua originale è stato scritto rv
, e successivamente !
, mentre B usa l'unario *
. Pertanto, se p
è una cella che contiene l'indice di (o l'indirizzo di) o il puntatore a) un'altra cella, si *p
riferisce al contenuto della cella puntata, sia come valore in un'espressione sia come target di un compito.
Dallo sviluppo del linguaggio C.
Questo è tutto. A questo punto, la domanda non è interessante come "perché Python 3 usa .
per chiamare un metodo? Perché no ->
?" Bene ... perché Python 2 usa .
per chiamare un metodo.
Raramente esiste una lingua dal nulla. Ha influenze e si basa su qualcosa che è venuto prima.
Quindi, perché B non ha usato !
per derefrittare un puntatore come ha fatto il suo predecessore BCPL?
Bene, BCPL era un po 'prolisso. Invece di &&
o ||
BCPL usato logand
e logor
. Questo perché la maggior parte delle tastiere non avevano ∧
o ∨
tasti e non uguali era in realtà la parola NEQV
(vedere il Manuale di riferimento BCPL ).
B sembra essere stato parzialmente ispirato a rafforzare la sintassi piuttosto che avere parole lunghe per tutti questi operatori logici che i programmatori hanno fatto abbastanza frequentemente. E così !
per la dereferenza divenne *
così che !
potesse essere usato per negazione logica. Nota che c'è una differenza tra l' *
operatore unario e l' *
operatore binario (moltiplicazione).
Bene, che dire di altre opzioni, come ->
?
Lo è ->
stato preso per lo zucchero sintattico attorno alle derefrenze di campo struct_pointer->field
che è(*struct_pointer).field
Altre opzioni come <-
potrebbero creare analisi ambigue. Per esempio:
foo <- bar
Deve essere letto come:
(foo) <- (bar)
o
(foo) < (-bar)
La creazione di un operatore unario composto da un operatore binario e un altro operatore unario ha probabilmente problemi in quanto il secondo operatore unario può essere un prefisso per un'altra espressione.
Inoltre, è di nuovo importante cercare di ridurre al minimo le cose che vengono digitate frequentemente. Vorrei odio dover scrivere:
int main(int argc, char->-> argv, char->-> envp)
Anche questo diventa difficile da leggere.
Potrebbero essere stati possibili altri personaggi (il @
non è stato usato fino a quando l' obiettivo C non lo si è appropriato ). Anche se, questo va al nocciolo di "C usi *
perché B ha fatto". Perché B non l'ha usato @
? Bene, B non ha usato tutti i personaggi. Non esisteva un bpp
programma (confronta cpp ) e altri caratteri erano disponibili in B (come quello #
che è stato successivamente utilizzato da cpp).
Se posso azzardare un'ipotesi sul perché - è a causa di dove si trovano le chiavi. Da un manuale su B :
Per facilitare la manipolazione degli indirizzi quando sembra opportuno, B fornisce due operatori di indirizzi unari *
e &
. &
è l'operatore di indirizzo così &x
è l'indirizzo di x
, supponendo che ne abbia uno. *
è l'operatore indiretto; *x
significa "usa il contenuto di x come indirizzo".
Si noti che &
è shift-7 ed *
è shift-8. La loro vicinanza reciproca potrebbe essere stata un suggerimento per il programmatore su ciò che fanno ... ma è solo una supposizione. Bisognerebbe chiedere a Ken Thompson perché è stata fatta questa scelta.
Così il gioco è fatto. C è così perché B lo era. B è così perché voleva cambiare da come era BCPL.
->
viene utilizzato nel linguaggio C come operatore di dereference - quando si accede ai campi in una struttura:,struct_pointer->field
che è l'abbreviazione di(*struct_pointer).field
.