En C y C++, las matrices no se pasan por valor

En C y C++, las matrices no se pasan por valor

El fragmento está tomado del juego ‘Wolf '. El código contiene un error que el analizador diagnostica de la siguiente manera:V511 El operador sizeof() devuelve el tamaño del puntero, y no del arreglo, en la expresión 'sizeof (src)'.

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );
}

Explicación

A veces, los programadores olvidan que en C/C++ no se puede pasar una matriz a una función por valor. Esto se debe a que se pasa un puntero a una matriz como argumento. Los números entre corchetes no significan nada, solo sirven como una especie de pista para el programador, qué tamaño de matriz se supone que debe pasar. De hecho, puede pasar una matriz de un tamaño completamente diferente. Por ejemplo, el siguiente código se compilará con éxito:

void F(int p[10]) { }
void G()
{
  int p[3];
  F(p);
}

En consecuencia, el sizeof(src) El operador no evalúa el tamaño de la matriz, sino el tamaño del puntero. Como resultado, memcpy() solo copiará parte de la matriz. Es decir, 4 u 8 bytes, según el tamaño del puntero (las arquitecturas exóticas no cuentan).

Código correcto

La variante más simple de dicho código puede ser así:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy(mat, src, sizeof(float) * 3 * 3);
}

Recomendación

Hay varias formas de hacer que su código sea más seguro.

Se conoce el tamaño de la matriz. Puede hacer que la función tome la referencia a una matriz. Pero no todos saben que puedes hacer esto, y aún menos personas saben cómo escribirlo. Así que espero que este ejemplo sea interesante y útil:

ID_INLINE mat3_t::mat3_t( float (&src)[3][3] )
{
  memcpy( mat, src, sizeof( src ) );
}

Ahora, será posible pasar a la función una matriz solo del tamaño correcto. Y lo más importante, el sizeof() El operador evaluará el tamaño de la matriz, no un puntero.

Otra forma más de resolver este problema es comenzar a usar std::array clase.

No se conoce el tamaño de la matriz. Algunos autores de libros de programación aconsejan utilizar la clase std::vector, y otras clases similares, pero en la práctica no siempre es conveniente.

A veces desea trabajar con un puntero simple. En este caso, debe pasar dos argumentos a la función:un puntero y el número de elementos. Sin embargo, en general, esta es una mala práctica y puede generar muchos errores.

En tales casos, puede ser útil leer algunos pensamientos proporcionados en las "Pautas básicas de C++". Sugerimos leer “No pase una matriz como un solo puntero“. En general, sería bueno leer las "Pautas básicas de C ++" siempre que tenga tiempo libre. Contiene muchas ideas útiles.

Escrito por Andrey Karpov.
Este error se encontró con PVS-Studio herramienta de análisis estático.