Macro de longitud de matriz común para C?

He visto varias macros para la longitud de la matriz flotando:

De esta pregunta :

  • #define length(array) (sizeof(array)/sizeof(*(array)))
  • #define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
  • #define SIZE(array, type) (sizeof(array) / (sizeof(type))

Y el _countof Visual Studio:

 #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) 

Lo que me gustaría saber es:

  1. ¿Cuál es la diferencia entre aquellos que usan array[0] y *array ?
  2. ¿Por qué debería ser preferido?
  3. ¿Difieren en C ++?

Aquí hay una mejor versión C (del proyecto Chromium de Google):

 #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 

Mejora la array[0] o *array versión de *array utilizando 0[array] , que es equivalente a la array[0] en matrices simples, pero no podrá comstackr si la array es un tipo de C ++ que sobrecarga al operator[]()

La división provoca una operación de división por cero (que se debe capturar en tiempo de comstackción, ya que es una expresión constante en tiempo de comstackción) para muchas (pero no todas) situaciones en las que se pasa un puntero como parámetro de la array .

Ver ¿Hay una función estándar en C que devuelva la longitud de una matriz? para más detalles.

Hay una mejor opción para el código C ++. Consulte Tiempo de comstackción sizeof_array sin usar una macro para más detalles.

  1. ¿Cuál es la diferencia entre aquellos que usan array [0] y * array?
  2. ¿Por qué debería ser preferido?
  3. ¿Difieren en C ++?

(1) No hay diferencia en C. No hay diferencia para una matriz cruda real en C ++.

(2) No hay motivos técnicos para preferir uno u otro, pero los principiantes pueden confundirse con la desreferencia del puntero.

(3) En C ++ normalmente no usaría la macro, porque es muy insegura. Si pasa un puntero en lugar de una matriz cruda real, el código se comstackrá pero arrojará resultados incorrectos. Entonces en C ++ deberías / deberías usar una plantilla de función, como …

 #include  typedef ptrdiff_t Size; template< class Type, Size n > Size countOf( Type (&)[n] ) { return n; } 

Esto solo acepta una matriz cruda real como argumento.

Es parte de una tríada de funciones startOf , endOf y countOf que es muy conveniente definir para que se puedan aplicar tanto a matrices en bruto como a contenedores de bibliotecas estándar. Por lo que sé, esta tríada fue identificada por primera vez por Dietmar Kuehl. En C ++ 0x startOf y endOf probablemente estarán disponibles como std::begin y std::end .

Saludos y hth.,

1) Nada, el valor de una matriz es un puntero a su primer elemento. Entonces * array == array [0]
2) Preferencia personal
3) No

Tenga en cuenta que esta macro no funcionará si se llama dentro de una función donde la matriz se transfiere como un parámetro a la función. Esto se debe a que el objeto de la matriz pasado “decae” en un puntero en lugar de una copia profunda.