Konstante Zeiger auf Zeiger auf Zeiger ...

Einführung


Kürzlich kamen sie mit der Frage auf mich zu, was es ist und wie man es benutzt. Sie zeigten den folgenden Code:

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

Dieser Kollege war mein Arbeitskollege und wir haben nicht sofort verstanden, was genau die Parameter in der Funktionsdeklaration bedeuten (für diejenigen, die interessiert sind, wo eine solche Ankündigung erforderlich sein könnte: in der Kryptographie).

Und im Vorgriff auf mögliche Probleme von Kollegen im Workshop habe ich beschlossen, diesen Artikel zu erstellen und ihn als Spickzettel zu verwenden, nämlich die Antworten auf zwei Fragen:

  1. Wie schreibe ich solche Anzeigen hier?
  2. Und wie liest man sie richtig?

"*"


Der Fall mit einem Stern ist am häufigsten, aber auch hier sind Missverständnisse möglich:

  • Wie richtig:

    • Also:

       const byte p; 
    • Oder so:

       byte const p; 

  • Oder im Fall des Eintrags '*':

    • Also:

       byte *const p; 
    • Oder so:

       const byte *p; 

Genau genommen wirft das Vorhandensein eines Sterns und seine Position im Ausdruck aus Sicht des Compilers eine Randfrage auf, weil Die endgültige Bedeutung des Eintrags ist unterschiedlich. Das Vorhandensein des const-Spezifizierers im obigen Fall macht keinen Unterschied, wenn seine Position relativ zum Datentyp berücksichtigt wird. Die Situation ändert sich jedoch dramatisch, wenn Zeiger angezeigt werden: eins, zwei, drei ... Nun, Sie verstehen:

 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]++; // . } 

All dies sieht interessanter aus, wenn der zweite Zeiger erscheint (hier beginnt bereits eine effiziente Leseregel zum Schreiben zu verfolgen):

 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]++; // . } 

Wie Sie sehen können, kann ein Doppelzeiger auf bis zu 8 verschiedene Arten dargestellt werden, von denen jede eine spezielle Art der Verwendung der Zieldaten definiert.

Die Regeln zum Lesen solcher Ausdrücke lauten wie folgt:

  • Suchen Sie im Ausdruck nach dem Zeichen '=' und lesen Sie den Ausdruck von rechts nach links.
  • Überspringen Sie den Namen der Variablen.
  • weitere Besprechungen entweder '*', was einen regulären Zeiger bedeutet, oder '* const' - ein konstanter Zeiger;
  • also lesen wir, bis der Datentyp (Byte) angetroffen wird;
  • und das letzte Wort links vom Datentyp kann const sein, dessen Vorhandensein bedeutet, dass sich diese gesamte Konstruktion auf Daten bezieht, die nicht geändert werden können; Wenn const nicht ist, ist es möglich.

Diese Form des Schreibens und Lesens erleichtert das Lesen und Verstehen selbst der anspruchsvollsten Ausdrücke.

Hier ist ein Beispiel für einen vollständigen Satz von Ausdrücken mit einem dreifachen Zeiger:

***


 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/de468605/


All Articles