Saltar al contenido

preprocesador c – macro ARRAYSIZE C ++: ¿cómo funciona?

octubre 21, 2021
apple touch icon@2

Escribí esta versión de esta macro. Considere la versión anterior:

#include <sys/stat.h>
#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))

int main(int argc, char *argv[]) {
  struct stat stats[32];
  std::cout << "sizeof stats = " << (sizeof stats) << "n";
  std::cout << "sizeof *stats = " << (sizeof *stats) << "n";
  std::cout << "ARRAYSIZE=" << ARRAYSIZE(stats) << "n";

  foo(stats);
}

void foo(struct stat stats[32]) {
  std::cout << "sizeof stats = " << (sizeof stats) << "n";
  std::cout << "sizeof *stats = " << (sizeof *stats) << "n";
  std::cout << "ARRAYSIZE=" << ARRAYSIZE(stats) << "n";
}

En una máquina de 64 bits, este código produce esta salida:

sizeof stats = 4608
sizeof *stats = 144
ARRAYSIZE=32
sizeof stats = 8
sizeof *stats = 144
ARRAYSIZE=0

¿Qué pasa? ¿Cómo pasó ARRAYSIZE de 32 a cero? Bueno, el problema es que el parámetro de la función es en realidad un puntero, aunque parece una matriz. Entonces, dentro de foo, «sizeof (stats)» tiene 8 bytes y «sizeof (* stats)» sigue siendo 144.

Con la nueva macro:

#define ARRAYSIZE(a) 
  ((sizeof(a) / sizeof(*(a))) / 
  static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))

Cuando sizeof (a) no es un múltiplo de sizeof (* (a)), el% no es cero, lo que el! invierte, y luego static_cast se evalúa a cero, lo que provoca una división en tiempo de compilación por cero. Entonces, en la medida de lo posible en una macro, esta extraña división detecta el problema en tiempo de compilación.

PD: en C ++ 17, solo use std :: size, vea http://en.cppreference.com/w/cpp/iterator/size

close