Je vais vous interpréter votre question à deux questions: 1) pourquoi est - ->
il existe encore, et 2) pourquoi est - .
ne met pas automatiquement à déréférencer le pointeur. Les réponses à ces deux questions ont des racines historiques.
Pourquoi est - ->
même exister?
Dans une des premières versions du langage C (je ferai référence en tant que CRM pour "C Manuel de Référence"), l'opérateur ->
avait très exclusif sens, ne sont pas synonymes *
et .
combinaison
Dennis M. Ritchie - C Manuel De Référence
Le langage C décrit par le CRM a été très différente de la moderne C à bien des égards. En CRM les membres de la structure mis en œuvre le concept global de décalage, c'est à dire tous les noms de tous les membres de la structure avait indépendant sens global (et, par conséquent, devait être unique). Par exemple, vous pourriez déclarer
struct S {
int a;
int b;
};
et nom a
tiendrait à l'offset 0, tandis que le nom de l' b
se offset 2 (en supposant int
type de taille 2 et aucun rembourrage). La langue exigé que tous les membres de toutes les structures dans l'unité de traduction, soit ont des noms uniques ou de stand pour la même valeur de décalage. E. g. dans la même unité de traduction, vous pouvez en plus de déclarer
struct X {
int a;
int x;
};
et qui serait OK, depuis que le nom de l' a
serait constamment stand de décalage 0. Mais cette déclaration supplémentaire
struct Y {
int b;
int a;
};
formellement valide, puisqu'il a tenté de "redéfinir" a
offset 2 et b
offset 0.
Et c'est là que l' ->
de l'opérateur. Puisque chaque struct nom de membre avait sa propre auto-suffisante sens, la langue prise en charge des expressions comme ces
int i = 5;
i->b = 42; /* Write 42 into `int` at address 7 */
100->a = 0; /* Write 0 into `int` at address 100 */
La première mission a été interprété par le compilateur comme "prendre l'adresse 5
, ajoutez un décalage 2
à et de lui attribuer 42
de la int
de la valeur à la résultante de l'adresse". I. e. ci-dessus à attribuer, 42
de int
de la valeur à l'adresse 7
. Notez que cette utilisation de l' ->
ne se soucient pas le type de l'expression sur le côté gauche. Le côté gauche a été interprété comme une rvalue adresse numérique (que ce soit un pointeur ou un entier).
Ce genre de supercherie n'était pas possible avec *
et .
combinaison. Vous ne pourriez pas faire
(*i).b = 42;
depuis *i
est déjà une défaillance de l'expression. L' *
de l'opérateur, depuis qu'il est séparé de .
, impose plus strictes en matière de type de son opérande. Pour fournir une capacité permettant de contourner cette limitation CRM introduit l' ->
opérateur, qui est indépendant du type de la partie gauche de l'opérande.
Comme Keith noté dans les commentaires, cette différence entre ->
et *
+.
combinaison est ce que le CRM est, en se référant à "la relaxation de l'exigence" dans 7.1.8: Sauf pour l'assouplissement de l'exigence d' E1
être de type pointeur, l'expression E1−>MOS
est exactement équivalent à (*E1).MOS
Plus tard, dans le K&R C de nombreuses fonctionnalités initialement décrite dans les CRM ont été considérablement retravaillé. L'idée de "struct membre de global offset identificateur" a été entièrement supprimé. Et la fonctionnalité de l' ->
opérateur est devenu totalement identique à la fonctionnalité de l' *
et .
combinaison.
Pourquoi ne peut - .
déréférencer le pointeur automatiquement?
Encore une fois, dans CRM version de la langue de l'opérande gauche de l' .
de l'opérateur devait être une lvalue. Que c'était la seule obligation que lui impose l'opérande (et c'est ce qui le rend différent de ->
, comme expliqué ci-dessus). Notez que le CRM n'a pas besoin de l'opérande gauche de l' .
d'avoir un type struct. Il a juste tenu à être une lvalue, tout lvalue. Cela signifie que dans le CRM version de C, vous pouvez écrire le code comme ceci
struct S { int a, b; };
struct T { float x, y, z; };
struct T c;
c.b = 55;
Dans ce cas, le compilateur pourrait écrire 55
en int
de la valeur positionnée à l'octet d'offset de 2 dans la mémoire continue de bloquer connu comme c
, même si le type struct T
n'avait pas de champ nommé b
. Le compilateur ne serait pas de soins sur le type réel de l' c
. Tous il se souciait est qu' c
est une lvalue: une sorte d'écriture de bloc de mémoire.
Maintenant, notez que si vous avez fait cela
S *s;
...
s.b = 42;
le code serait considéré comme valide (depuis s
est également une lvalue) et le compilateur aurait simplement tenter d'écrire des données dans le pointeur s
lui-même, à l'octet d'offset de 2. Inutile de dire, ce genre de choses pourrait facilement provoquer de dépassement de capacité de la mémoire, mais la langue n'a pas à se préoccuper de ces questions.
I. e. dans la version de la langue de votre idée à propos de la surcharge de l'opérateur .
pour les types pointeur ne fonctionnerait pas: opérateur .
avaient déjà sens très précis lorsqu'il est utilisé avec des pointeurs (avec lvalue pointeurs ou avec toute lvalues à tous). C'était très bizarre fonctionnalité, sans aucun doute. Mais il était là à l'époque.
Bien sûr, cela bizarre fonctionnalité n'est pas une très bonne raison contre l'introduction surchargé .
de l'opérateur pour les pointeurs (comme vous l'avez suggéré) dans la version remaniée de C - K&R C. Mais il n'a pas été fait. Peut-être qu'à cette époque il y avait un code existant écrit en CRM version de C qui a dû être pris en charge...