Pointeurs constants à pointeurs à pointeurs ...

Présentation


Récemment, ils m'ont approché avec la question «qu'est-ce que c'est et comment l'utiliser?», Montrant le code suivant:

extern "C" { void byteMaskDowngrade(byte***const byteMask, const byte *const *const && source) { // - . } //  . } 

Ce collègue était mon collègue de travail, et nous n'avons pas immédiatement compris ce que signifient exactement les paramètres dans la déclaration de fonction (pour ceux qui sont intéressés où une telle annonce pourrait être nécessaire: en cryptographie).

Et en prévision d'éventuels problèmes de collègues de l'atelier, j'ai décidé de créer cet article, en le mettant sous forme de triche, à savoir les réponses à deux questions:

  1. Comment écrire de telles annonces ici?
  2. Et comment les lire correctement?

"*"


Le cas avec un astérisque est le plus courant, cependant, des malentendus sont également possibles ici:

  • Comment:

    • Donc:

       const byte p; 
    • Ou alors:

       byte const p; 

  • Ou dans le cas de l'entrée «*»:

    • Donc:

       byte *const p; 
    • Ou alors:

       const byte *p; 

A strictement parler, du point de vue du compilateur, la présence d'un astérisque et sa position dans l'expression pose une question de fond car la signification finale de l'entrée sera différente. La présence du spécificateur const dans le cas ci-dessus ne fait aucune différence lorsque l'on considère sa position par rapport au type de données, cependant, la situation change considérablement lorsque des pointeurs apparaissent: un, deux, trois ... eh bien, vous comprenez:

 void p() { //   . byte * a = new byte{1}; a++; // . a[0]++; // . //    . const byte * b = new byte{1}; b++; // . //b[0]++; // . //    . byte *const c = new byte{1}; //c++; // . c[0]++; // . //     . const byte *const d = new byte{1}; //d++; // . //d[0]++; // . } 

Tout cela semble plus intéressant lorsque le deuxième pointeur apparaît (ici une règle de lecture efficace pour l'écriture commence déjà à être tracée):

 void pp() { //     . byte ** a = new byte * { new byte{1} }; a++; // . a[0]++; // . a[0][0]++; // . //      . const byte ** b = new const byte * { new byte{1}}; b++; // . b[0]++; // . //b[0][0]++; // . //      . byte *const * c = new byte * { new byte{1}}; c++; // . //c[0]++; // . c[0][0]++; // . //      . byte * *const d = new byte * { new byte{1}}; //d++; // . d[0]++; // . d[0][0]++; // . //       . const byte *const * e = new const byte *const { new byte{1}}; e++; // . //e[0]++; // . //e[0][0]++; // . //       . const byte * *const f = new const byte * { new byte{1}}; //f++; // . f[0]++; // . //f[0][0]++; // . //       . byte *const *const g = new byte *const { new byte{1}}; //g++; // . //g[0]++; // . g[0][0]++; // . //        . const byte *const *const h = new const byte *const { new byte{1}}; //h++; // . //h[0]++; // . //h[0][0]++; // . } 

Comme vous pouvez le voir, un double pointeur peut être représenté de 8 façons différentes, chacune définissant une manière spéciale d'utiliser les données cibles.

Les règles de lecture de telles expressions sont les suivantes:

  • recherchez le signe «=» dans l'expression et lisez l'expression de droite à gauche;
  • ignorer le nom de la variable;
  • d'autres réunions soit '*', qui signifie un pointeur régulier, soit '* const' - un pointeur constant;
  • ainsi nous lisons jusqu'à ce que le type de données (octet) soit rencontré;
  • et le dernier mot à gauche du type de données peut être const, dont la présence signifie que toute cette construction fait référence à des données qui ne peuvent pas être modifiées; si const ne l'est pas, alors c'est possible.

Cette forme d'écriture et de lecture facilite la lecture et la compréhension des expressions les plus sophistiquées)

Voici un exemple d'un ensemble complet d'expressions avec un triple pointeur:

"***"


 void ppp() { //       . byte *** a = new byte * * { new byte * {new byte{1}} }; a++; // . a[0]++; // . a[0][0]++; // . a[0][0][0]++; // . //        . const byte *** b = new const byte * * { new const byte * {new byte{1}} }; b++; // . b[0]++; // . b[0][0]++; // . //b[0][0][0]++; // . //        . byte*const * * c = new byte *const * { new byte *const {new byte{1}} }; c++; // . c[0]++; // . //c[0][0]++; // . c[0][0][0]++; // . //        . byte * *const * d = new byte * *const { new byte * {new byte{1}} }; d++; // . //d[0]++; // . d[0][0]++; // . d[0][0][0]++; // . //        . byte *** const e = new byte * * { new byte * {new byte{1}} }; //e++; // . e[0]++; // . e[0][0]++; // . e[0][0][0]++; // . //         . const byte *const * * f = new const byte *const * { new const byte *const {new byte{1}} }; f++; // . f[0]++; // . //f[0][0]++; // . //f[0][0][0]++; // . //         . const byte * *const * g = new const byte * *const{ new const byte * {new byte{1}} }; g++; // . //g[0]++; // . g[0][0]++; // . //g[0][0][0]++; // . //         . const byte * * *const h = new const byte * *{ new const byte * {new byte{1}}}; //h++; // . h[0]++; // . h[0][0]++; // . //h[0][0][0]++; // . //         . byte *const * *const i = new byte *const * { new byte *const {new byte{1}}}; //i++; // . i[0]++; // . //i[0][0]++; // . i[0][0][0]++; // . //         . byte * *const *const j = new byte * *const { new byte * {new byte{1}}}; //j++; // . //j[0]++; // . j[0][0]++; // . j[0][0][0]++; // . //         . byte *const *const * k = new byte *const *const {new byte *const{new byte{1}}}; k++; // . //k[0]++; // . //k[0][0]++; // . k[0][0][0]++; // . //           const //           . const byte *const *const *const m = new const byte *const *const {new const byte *const {new byte{1}}}; //m++; // . //m[0]++; // . //m[0][0]++; // . //m[0][0][0]++; // . } 

Source: https://habr.com/ru/post/fr468605/


All Articles