58 votes

Pourquoi l'opérateur de déréférencement (*) est-il également utilisé pour déclarer un pointeur ?

Je ne suis pas sûr qu'il s'agisse d'une bonne question de programmation, mais c'est quelque chose qui m'a toujours dérangé, et je me demande si je suis le seul.

Au début de mon apprentissage du C++, j'ai compris le concept des références, mais les pointeurs m'ont laissé perplexe. Pourquoi, me demandez-vous ? À cause de la façon dont on déclare un pointeur.

Considérez ce qui suit :

void foo(int* bar)
{
}

int main()
{
    int x = 5;
    int* y = NULL;

    y = &x;
    *y = 15;     
    foo(y);

}

La fonction foo(int*) prend un int comme paramètre. Puisque j'ai déclaré y comme int pointeur, je peux passer y a foo mais lorsque j'ai commencé à apprendre le C++, j'ai associé l'option * avec déréférencement, j'ai donc pensé qu'un symbole déréférencé int devait être adoptée. J'essaierais de faire passer *y en foo ce qui, de toute évidence, ne fonctionne pas.

N'aurait-il pas été plus simple d'avoir un opérateur séparé pour déclarer un pointeur ? (ou pour le déréférencement). Par exemple :

void test(int@ x)
{
}

11 votes

On ne peut pas répondre à cette question, on ne peut que spéculer.

0 votes

Qu'y a-t-il de mal à faire preuve d'une véritable curiosité ?

0 votes

@diggingforfire : Rien, mais ce n'est pas à ça que sert le SO. Essayez Programmeurs.SE pour les questions à débattre.

87voto

Crashworks Points 22920

Sur Le développement du langage C Dennis Ritchie explique ainsi son raisonnement :

La deuxième innovation qui distingue le plus clairement le C de ses prédécesseurs est cette structure de type plus complète et surtout son expression dans la syntaxe des déclarations... étant donné un objet de n'importe quel type de n'importe quel type, il devrait être possible de décrire un nouvel objet qui en rassemble plusieurs dans un tableau, le rend à partir d'une fonction, ou est un pointeur vers it.... [Ceci] a conduit à une syntaxe de déclaration pour les noms reflétant celle de la syntaxe d'expression dans laquelle les noms apparaissent généralement. Ainsi,

int i, *pi, **ppi; déclarer un nombre entier, un pointeur vers un nombre entier, un un pointeur vers un pointeur vers un entier. La syntaxe de ces déclarations reflète l'observation que i, *pi, and **ppi donnent tous un int type lorsqu'il est utilisé dans une expression.

De même, int f(), *f(), (*f)(); déclarer une fonction retournant un entier, une fonction retournant un pointeur vers un entier, un pointeur vers une fonction retournant un entier. un pointeur vers un entier, un pointeur vers une fonction retournant un entier. int *api[10], (*pai)[10]; déclare un tableau de pointeurs sur des entiers, et un pointeur sur un tableau d'entiers.

Dans tous ces cas, la déclaration d'une variable ressemble à son utilisation dans une expression dont le type est celui nommé en tête de la déclaration .

Un accident de syntaxe a contribué à la complexité perçue de la langue. L'opérateur d'indirection, orthographié * en C, est syntaxiquement un op préfixe unaire préfixe unaire, comme dans BCPL et B. Cela fonctionne bien dans les expressions expressions simples, mais dans les cas plus complexes, les parenthèses sont sont nécessaires pour diriger l'analyse syntaxique. Par exemple, pour distinguer l'indirection par la valeur retournée par une fonction de l'appel d'une fonction désignée par un pointeur, on écrit *fp() and (*pf)() respectivement. Le style utilisé dans les expressions se retrouve dans les de sorte que les noms peuvent être déclarés

int *fp(); int (*pf)();

Dans des cas plus ornés mais toujours réalistes, les choses s'aggravent : int *(*pfp)(); est un pointeur vers une fonction retournant un pointeur vers un entier.

Il y a deux effets qui se produisent. Le plus important est que C dispose d'un ensemble relativement riche de moyens de décrire les types (comparé, par exemple, à Pascal). Les déclarations dans des langages aussi expressifs comme le C-Algol 68, par exemple-décrivent des objets tout aussi difficiles à difficile à comprendre, simplement parce que les objets eux-mêmes sont complexes. A deuxième effet est dû aux détails de la syntaxe. Les déclarations en C doivent être doivent être lues dans un style "à l'envers" que beaucoup trouvent difficile à comprendre. Sethi [Sethi 81] a observé que de nombreuses déclarations et expressions imbriquées seraient plus simples si l'opérateur d'indirection avait été considéré comme un opérateur postfixe au lieu d'un opérateur préfixe, mais mais il était alors trop tard pour changer.

5 votes

C'est une excellente explication, j'aurais aimé qu'on nous dise ce genre de choses en classe, cela m'aurait aidé à comprendre les pointeurs beaucoup plus tôt.

0 votes

C'est très utile ! Je me suis toujours interrogé sur la syntaxe étrange des pointeurs de fonction. Connaître le contexte rend leur lecture et leur écriture beaucoup plus facile. J'adore ce site Web <3

3 votes

@Tomalak Geret'kal : Shucks, dommage que je ne puisse pas l'éditer maintenant. Eh bien, ce sont des choses qui arrivent quand on écrit dans une langue étrangère.

17voto

Stuart Golodetz Points 12679

La raison est plus claire si vous l'écrivez comme ceci :

int x, *y;

C'est-à-dire que x et *y sont tous deux des ints. Ainsi, y est un int *.

0 votes

En fait, ce n'est pas plus clair si on le développe. Je ne veux pas lancer une polémique, mais je voudrais faire remarquer que cette syntaxe va forcément en entraîner une.

1 votes

Je suis d'accord que vous ne devriez pas utiliser cette syntaxe dans la pratique - il s'agissait simplement d'illustrer le propos (qui est le même que celui de David).

0 votes

En effet, rien contre vous ou votre réponse (sauf peut-être la partie "plus claire")

10voto

Il s'agit d'une décision de langage antérieure à C++, puisque C++ a hérité de C. J'ai entendu dire une fois que la motivation était que la déclaration et l'utilisation seraient équivalentes, c'est-à-dire qu'étant donné une déclaration int *p; l'expression *p est de type int de la même manière qu'avec int i; l'expression i est de type int .

8voto

Parce que le comité, et ceux qui ont développé le C++ dans les décennies précédant sa standardisation, ont décidé que *`` doit conserver ses trois significations originales** :

  • Un type de pointeur
  • L'opérateur de déréférencement
  • Multiplication

Vous avez raison de suggérer que les multiples significations de * (et, de la même manière, & ) sont déroutants. Je pense depuis quelques années qu'ils constituent un obstacle important à la compréhension pour les nouveaux venus dans la langue.


Pourquoi ne pas choisir un autre symbole pour C++ ?

Compatibilité descendante est la cause première... il vaut mieux réutiliser des symboles existants dans un nouveau contexte que de casser des programmes C en traduisant des opérateurs qui n'existaient pas auparavant dans de nouvelles significations.


Pourquoi ne pas choisir un autre symbole pour C ?

Il est impossible d'en être sûr, mais plusieurs arguments peuvent être - et ont été - avancés. Le plus important est l'idée que :

lorsqu'un identificateur apparaît dans une expression de la même forme que le déclarateur, il produit un objet du type spécifié. {K&R, p216}

C'est aussi pourquoi les programmeurs C ont tendance à [citation nécessaire] préfèrent aligner leurs astérisques à droite plutôt qu'à gauche, c'est-à-dire :

int *ptr1; // roughly C-style
int* ptr2; // roughly C++-style

bien que les deux variétés se retrouvent dans les programmes des deux langues, de manière variable.

3 votes

Je ne pense pas que le comité ait décidé quoi que ce soit ; c'est probablement Dennis Ritchie qui a créé C.

0 votes

Le comité est responsable de la langue que nous connaissons aujourd'hui. C'est vrai, ça a commencé avec DR, mais ce n'est pas le "C" tel que nous le connaissons aujourd'hui. Et, plus que toute autre chose, le comité C++ a pris la décision consciente pour le langage C++ -- Ritchie ne l'a pas fait.

8 votes

Avant qu'il y ait un comité, Ritchie a inventé cette syntaxe. Stroustrup n'allait pas rompre la rétrocompatibilité avec C en ne l'utilisant pas. Toutes ces décisions ont été prises avant que le développement du C et du C++ ne soit confié à un organisme de normalisation.

5voto

sarnold Points 62720

Page 65 de Programmation C experte : Les secrets du C profond comprend les éléments suivants : Et puis, il y a la philosophie du C qui veut que la déclaration d'un objet ressemble à son utilisation.

Page 216 de Le langage de programmation C, 2ème édition (aka K&R) comprend : Un déclarateur est lu comme une assertion selon laquelle, lorsque son identifiant apparaît dans une expression de la même forme que le déclarateur, celle-ci produit un objet du type spécifié.

Je préfère la façon dont van der Linden le présente.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X