Cada C programador puede determinar el número de elementos en una matriz con esta macro bien conocido:determinar de manera fiable el número de elementos en una matriz
#define NUM_ELEMS(a) (sizeof(a)/sizeof 0[a])
Aquí es un caso típico uso:
int numbers[] = {2, 3, 5, 7, 11, 13, 17, 19};
printf("%lu\n", NUM_ELEMS(numbers)); // 8, as expected
Sin embargo, nada impide que el programador se transfieran accidentalmente un puntero en lugar de una matriz:
int * pointer = numbers;
printf("%lu\n", NUM_ELEMS(pointer));
En mi sistema, esto imprime 2, porque aparentemente, un puntero es dos veces más grande que un entero. Pensé acerca de cómo prevenir el programador de pasar un puntero por error, y he encontrado una solución:
#define NUM_ELEMS(a) (assert((void*)&(a) == (void*)(a)), (sizeof(a)/sizeof 0[a]))
Esto funciona porque un puntero a una matriz tiene el mismo valor que un puntero a su primer elemento. Si pasa un puntero en su lugar, el puntero se comparará con un puntero a sí mismo, que casi siempre es falso. (La única excepción es un puntero nulo recursiva, es decir, un puntero nulo que apunta a sí puedo vivir con eso..)
pasar accidentalmente un puntero en lugar de una matriz ahora desencadena un error en tiempo de ejecución:
Assertion `(void*)&(pointer) == (void*)(pointer)' failed.
¡Agradable! Ahora tengo un par de preguntas:
Es mi uso de
assert
como el operando de la izquierda de la norma válida expresión con coma C? Es decir, ¿el estándar me permite usarassert
como expresión? Lo siento si esta es una pregunta tonta :)¿Se puede realizar el control de alguna manera en tiempo de compilación?
Mi compilador de C piensa que
int b[NUM_ELEMS(a)];
es un VLA. ¿Alguna forma de convencerlo de lo contrario?¿Soy el primero en pensar en esto? Si es así, ¿cuántas vírgenes puedo esperar para estar en el cielo? :)
En cuanto a la parte (4), bastante seguro de que es * no * 72. Creo que t sombrero de un valor reservado para otra cosa ... –
no ¿Quieres decir 'sizeof a [0]'? –
Cada programador c real sabe que no perder de vista el tamaño de las matrices es su problema, no los compiladores y trucos para que "la figura hacia fuera" son de utilidad estrictamente limitada debido a que la información sólo se retiene en su alcance.Si desea que el compilador se ocupe de esto por usted, use un lenguaje más inteligente. Quiero decir, solo necesitas ir a C++ y usar 'std :: vector' o (con C++ 11)' std :: array', así que no es un gran cambio. – dmckee