Punteros constantes a punteros a punteros ...

Introduccion


Recientemente se me acercaron con la pregunta "¿qué es y cómo usarla?", Mostrando el siguiente código:

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

Este colega era mi colega de trabajo, y no entendimos de inmediato qué significan exactamente los parámetros en la declaración de función (para aquellos que estén interesados ​​en un anuncio de este tipo: en criptografía).

Y en previsión de posibles problemas de colegas en el taller, decidí crear este artículo, poniéndolo como una hoja de trucos, es decir, las respuestas a dos preguntas:

  1. ¿Cómo escribir tales anuncios aquí?
  2. ¿Y cómo leerlos correctamente?

"*"


El caso con un asterisco es el más común, sin embargo, los malentendidos también son posibles aquí:

  • Cómo:

    • Entonces

       const byte p; 
    • Más o menos:

       byte const p; 

  • O en el caso de la entrada '*':

    • Entonces

       byte *const p; 
    • Más o menos:

       const byte *p; 

Estrictamente hablando, desde el punto de vista del compilador, la presencia de un asterisco y su posición en la expresión plantea una pregunta fundamental porque El significado final de la entrada será diferente. La presencia del especificador const en el caso anterior no hace ninguna diferencia al considerar su posición con respecto al tipo de datos, sin embargo, la situación cambia dramáticamente cuando aparecen punteros: uno, dos, tres ... bueno, usted comprende:

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

Todo esto parece más interesante cuando aparece el segundo puntero (aquí ya se está comenzando a rastrear una regla de lectura eficiente para escribir):

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

Como puede ver, un puntero doble puede representarse en hasta 8 formas diferentes, cada una de las cuales define una forma especial de utilizar los datos de destino.

Las reglas para leer tales expresiones son las siguientes:

  • busque el signo '=' en la expresión y lea la expresión de derecha a izquierda;
  • omita el nombre de la variable;
  • reuniones adicionales ya sea '*', que significa un puntero regular, o '* const' - un puntero constante;
  • así leemos hasta que se encuentre el tipo de datos (byte);
  • y la última palabra a la izquierda del tipo de datos puede ser constante, cuya presencia significa que toda esta construcción se refiere a datos que no se pueden cambiar; si no es constante, entonces es posible.

Esta forma de escribir y leer hace que sea fácil de leer y comprender incluso las expresiones más sofisticadas)

Aquí hay un ejemplo de un conjunto completo de expresiones con un puntero triple:

"***"


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


All Articles