Pourquoi C utilise-t-il l'astérisque pour les pointeurs?
Tout simplement - parce que B l'a fait.
La mémoire étant un tableau linéaire, il est possible d'interpréter la valeur d'une cellule comme un index dans ce tableau et BCPL fournit un opérateur à cet effet. Dans la langue d'origine, il était orthographié rv
, et plus tard !
, tandis que B utilise l'unaire *
. Ainsi, si p
est une cellule contenant l'index (ou l'adresse de), ou un pointeur vers) une autre cellule, *p
fait référence au contenu de la cellule pointée, soit comme valeur dans une expression, soit comme cible d'une affectation.
Du développement du langage C
C'est ça. À ce stade, la question est aussi inintéressante que "pourquoi python 3 utilise-t-il .
pour appeler une méthode? Pourquoi pas ->
?" Eh bien ... parce que Python 2 utilise .
pour appeler une méthode.
Il existe rarement une langue à partir de rien. Il a des influences et est basé sur quelque chose qui a précédé.
Alors, pourquoi B n'a-t-il pas utilisé !
pour déréfrencier un pointeur comme son prédécesseur BCPL?
Eh bien, BCPL était un peu verbeux. Au lieu de &&
ou ||
BCPL utilisé logand
et logor
. En effet, la plupart des claviers ne disposent pas de touches ∧
ou ∨
et ce n'est pas égal au mot NEQV
(voir le manuel de référence BCPL ).
B semble avoir été partiellement inspiré pour resserrer la syntaxe plutôt que d'avoir des mots longs pour tous ces opérateurs logiques que les programmeurs ont fait assez fréquemment. Et c'est ainsi !
que la déréférence est devenue *
ce qui !
pourrait être utilisé pour la négation logique. Notez qu'il y a une différence entre l' *
opérateur unaire et l' *
opérateur binaire (multiplication).
Et les autres options, comme ->
?
Le a ->
été pris pour le sucre syntaxique autour des déréfrences de champ struct_pointer->field
qui est(*struct_pointer).field
D'autres options comme <-
pourraient créer des analyses ambiguës. Par exemple:
foo <- bar
Est-ce à lire comme suit:
(foo) <- (bar)
ou
(foo) < (-bar)
La création d'un opérateur unaire composé d'un opérateur binaire et d'un autre opérateur unaire risque fort d'avoir des problèmes car le deuxième opérateur unaire peut être un préfixe pour une autre expression.
De plus, il est encore important d'essayer de réduire au minimum les éléments tapés fréquemment. Je détesterais devoir écrire:
int main(int argc, char->-> argv, char->-> envp)
Cela devient également difficile à lire.
D'autres personnages auraient pu être possibles (le @
n'a pas été utilisé avant que l' Objectif C ne s'en soit approprié ). Encore une fois, cela va au cœur de «C utilise *
parce que B l'a fait». Pourquoi B n'a-t-il pas utilisé @
? Eh bien, B n'a pas utilisé tous les personnages. Il n'y avait pas de bpp
programme (comparer cpp ) et d'autres caractères étaient disponibles en B (comme celui #
qui a ensuite été utilisé par cpp).
Si je peux me permettre de deviner pourquoi - c'est à cause de l'emplacement des clés. D'un manuel sur B :
Pour faciliter la manipulation des adresses quand cela semble souhaitable, B fournit deux opérateurs d'adresses unaires, *
et &
. &
est l'opérateur d'adresse tout &x
comme l'adresse de x
, en supposant qu'il en ait un. *
est l'opérateur d'indirection; *x
signifie "utiliser le contenu de x comme adresse".
Notez que &
c'est shift-7 et *
c'est shift-8. Leur proximité les uns avec les autres a peut-être été une indication pour le programmeur de ce qu'ils font ... mais ce n'est qu'une supposition. Il faudrait demander à Ken Thompson pourquoi ce choix a été fait.
Alors voilà. C est ainsi parce que B l'était. B est comme ça parce qu'il voulait changer de la façon dont BCPL était.
->
est utilisé dans le langage C comme opérateur de déréférence - lors de l'accès aux champs dans une structure:,struct_pointer->field
qui est l'abréviation de(*struct_pointer).field
.