Ponteiros constantes para ponteiros para ponteiros ...

1. Introdução


Recentemente, eles me abordaram com a pergunta “o que é e como usá-lo?”, Mostrando o seguinte código:

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

Esse colega era meu colega de trabalho e não entendemos imediatamente o que exatamente os parâmetros significam na declaração da função (para aqueles que estão interessados ​​em onde esse anúncio pode ser necessário: em criptografia).

E, antecipando possíveis problemas dos colegas do workshop, decidi criar este artigo, colocando-o como uma folha de dicas, ou seja, as respostas para duas perguntas:

  1. Como escrever esses anúncios aqui?
  2. E como lê-los corretamente?

"*"


O caso com um asterisco é o mais comum, no entanto, mal-entendidos também são possíveis aqui:

  • Como:

    • Então:

       const byte p; 
    • Ou então:

       byte const p; 

  • Ou no caso da entrada '*':

    • Então:

       byte *const p; 
    • Ou então:

       const byte *p; 

Estritamente falando, do ponto de vista do compilador, a presença de um asterisco e sua posição na expressão colocam uma questão de ponta porque o significado final da entrada será diferente. A presença do especificador const no caso acima não faz nenhuma diferença ao considerar sua posição em relação ao tipo de dados; no entanto, a situação muda drasticamente quando os ponteiros aparecem: um, dois, três ... bem, você entende:

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

Tudo isso parece mais interessante quando o segundo ponteiro aparece (aqui uma regra de leitura eficiente para a escrita já está começando a ser rastreada):

 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 você pode ver, um ponteiro duplo pode ser representado em até 8 maneiras diferentes, cada uma das quais define uma maneira especial de usar os dados de destino.

As regras para a leitura de tais expressões são as seguintes:

  • procure o sinal '=' na expressão e leia a expressão da direita para a esquerda;
  • pule o nome da variável;
  • reuniões adicionais ou '*', que significa um ponteiro regular, ou '* const' - um ponteiro constante;
  • assim, lemos até que o tipo de dados (byte) seja encontrado;
  • e a última palavra à esquerda do tipo de dados pode ser const, cuja presença significa que toda essa construção se refere a dados que não podem ser alterados; se const não for, então é possível.

Essa forma de escrever e ler facilita a leitura e a compreensão mesmo das expressões mais sofisticadas.

Aqui está um exemplo de um conjunto completo de expressões com um ponteiro triplo:

"***"


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


All Articles