Pergunta

Isto surgiu de esta resposta a uma pergunta anterior minha.É garantido que o compilador trate array[4][4] o mesmo que array[16]?

Por exemplo, qualquer uma das chamadas abaixo para api_func() esteja a salvo?

void api_func(const double matrix[4][4]);

// ...

{
  typedef double Matrix[4][4];

  double* array1 = new double[16];
  double array2[16];

  // ...

  api_func(reinterpret_cast<Matrix&>(array1));
  api_func(reinterpret_cast<Matrix&>(array2));
}
Foi útil?

Solução

Do padrão C++, referindo-se ao sizeof operador:

Quando aplicado a uma matriz, o resultado é o número total de bytes na matriz.Isto implica que o tamanho de uma matriz de n elementos é n vezes o tamanho de um elemento.

A partir disso, eu diria que double[4][4] e double[16] teria que ter a mesma representação subjacente.

Ou seja, dado

sizeof(double[4]) = 4*sizeof(double)

e

sizeof(double[4][4]) = 4*sizeof(double[4])

então nós temos

sizeof(double[4][4]) = 4*4*sizeof(double) = 16*sizeof(double) = sizeof(double[16])

Acho que um compilador compatível com os padrões teria que implementá-los da mesma forma, e acho que isso não é algo que um compilador quebraria acidentalmente.A forma padrão de implementar matrizes multidimensionais funciona conforme o esperado.Quebrar o padrão exigiria trabalho extra, provavelmente sem nenhum benefício.

O padrão C++ também afirma que um array consiste em elementos alocados contíguamente, o que elimina a possibilidade de fazer algo estranho usando ponteiros e preenchimento.

Outras dicas

Eu não acho que haja um problema com o preenchimento introduzido por ter um multidimensional variedade.

Cada elemento de uma matriz deve satisfazer os requisitos de preenchimento impostos pela arquitetura.Um array [N][M] sempre terá a mesma representação na memória que um de [M*N].

Cada elemento do array deve ser disposto sequencialmente na memória pelo compilador.As duas declarações, embora de tipos diferentes, têm a mesma estrutura de memória subjacente.

@Konrad Rodolfo:

Eu mesmo confundo esses dois (linha principal/coluna principal), mas sei disso:Está bem definido.

int x[3][5], por exemplo, é um array de tamanho 3, cujos elementos são arrays int de tamanho 5.(§6.5.2.1) Adicionando todas as regras do padrão sobre arrays, endereçamento, etc.você percebe que o segundo subscrito faz referência a números inteiros consecutivos, enquanto o primeiro subscrito fará referência a objetos consecutivos de 5 int.(Portanto, 3 é o número maior;você tem 5 ints entre x[1][0] e x[2][0].)

Eu ficaria preocupado com a adição de preenchimento para coisas como Matrix[5][5] para alinhar cada palavra de linha, mas isso poderia ser simplesmente minha própria superstição.

Uma questão maior é:você realmente precisa realizar tal elenco?

Embora você poder ser capaz de se safar, ainda seria mais legível e sustentável evitá-lo completamente.Por exemplo, você poderia usar consistentemente double[m*n] como o tipo real e, em seguida, trabalhar com uma classe que agrupa esse tipo e talvez sobrecarregar o operador [] para facilitar o uso.Nesse caso, você também pode precisar de uma classe intermediária para encapsular uma única linha - para que um código como my_matrix[3][5] ainda funcione conforme o esperado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top