Detección de matriz no coincidente inicializadores de enumeración

4 minutos de lectura

Deteccion de matriz no coincidente inicializadores de enumeracion
usuario694733

Cuando hago programación integrada con C, muchas veces me encuentro haciendo mapas con enumeración y matriz porque son rápidos y eficientes en memoria.

enum {
    ID_DOG = 0,
    ID_SPIDER,
    ID_WORM,
    ID_COUNT
};
int const NumberOfEyes[ID_COUNT] = {
    2,
    8,
    0
};

El problema es que, a veces, cuando agrego o elimino elementos, cometo un error y la enumeración y la matriz no están sincronizadas. Si la lista de inicializadores es demasiado larga, el compilador la detectará, pero no al revés.

Entonces, ¿hay una verificación de tiempo de compilación confiable y portátil que la lista de inicializadores coincida con la longitud de la matriz?

Deteccion de matriz no coincidente inicializadores de enumeracion
Oliver Charlesworth

Esta es posiblemente una situación en la que X macros podría aplicarse.

animales.x

X(DOG,    2)
X(SPIDER, 8)
X(WORM,   0)

foo.c

enum {
#define X(a,b) ID_##a,
#include "animals.x"
#undef X
};

int const numberOfEyes[] = {
#define X(a,b) b,
#include "animals.x"
#undef X
};

Esto no solo garantiza que las longitudes coincidan, sino también que los pedidos se mantengan siempre sincronizados.

  • Excelente respuesta, este es el mismo problema con el que estaba luchando antes de descubrir el poder de x-macros. Consulte stackoverflow.com/questions/6635851/real-world-use-of-x-macros

    – ACRL

    4 mayo 2012 a las 12:50

  • Corregí un error en la respuesta; tenía cada una de las líneas en el archivo animals.x con el prefijo #define, cuando deberían estar expandiendo la macro en lugar de (re)definirla.

    – Brooks Moisés

    5 mayo 2012 a las 19:48

  • ¿Soy solo yo o las X-macros también causan cáncer de ojo a otros? 🙂 Como es make y la generación automática de dependencias afectadas? ¿Qué pasa con las herramientas de refactorización? ¿A los formateadores de código fuente les gusta la sangría?

    – Jens

    5 mayo 2012 a las 19:59


  • Soy un gran admirador de las x-macros, pero un colega señaló que hacen que la depuración sea un poco complicada. Si esto es algo en lo que es probable que necesite capacidad de depuración, puede intentar usar cog o similar en su lugar.

    – Vicky

    5 mayo 2012 a las 20:38

  • @Jens: X-macros son solo una combinación de archivos de encabezado y macros; si una herramienta no puede hacer frente a ellos, entonces podría decirse que es una falla de esa herramienta. Pero aprecio que los depuradores o el autocompletado del código IDE a menudo tropiezan con las macros. Dicho esto, personalmente no he encontrado una situación en la que esto haya sido problemático (por ejemplo, mis dependencias generadas automáticamente parecen funcionar bien).

    –Oliver Charlesworth

    5 mayo 2012 a las 20:40


1647702607 361 Deteccion de matriz no coincidente inicializadores de enumeracion
Jens

¿Qué pasa con una afirmación de tiempo de compilación como la siguiente? (Sí, hay macros CT_ASSERT más elaboradas; esto es para ilustrar la idea).

#define CT_ASSERT(expr, name) typedef char name[(expr)?1:-1]

enum {
    ID_DOG = 0,
    ID_SPIDER,
    ID_WORM,
    ID_COUNT
};

int const NumberOfEyes[] = {
    2,
    8,
    0
};

CT_ASSERT (sizeof NumberOfEyes/sizeof *NumberOfEyes == ID_COUNT, foo);

Ahora cuando el NumberOfEyes matriz tiene más o menos elementos que ID_COUNTesto causará un error a lo largo x.c:15: error: size of array 'foo' is negative. Las dimensiones de matriz negativas son una violación de restricción que debe ser diagnosticada por cualquier compilador de C.

  • El parámetro de nombre de la macro no es necesario si se asegura de que la macro se declare en un ámbito local. #define CT_ASSERT(expr) { typedef char ct_assert[(expr)?1:-1]; }.

    – Lundin

    7 de mayo de 2012 a las 8:33

  • Cierto, pero ¿por qué limitarse a bloquear el alcance? Tengo una serie de matrices de alcance de archivos que también deben verificarse. El uso de un nombre bien seleccionado también dará una pista en el mensaje de error del compilador sobre cuál es exactamente el problema, por ejemplo, en lugar de foo yo usaría enum_mismatch_in_NumberOfEyes.

    – Jens

    7 de mayo de 2012 a las 9:21

  • Dado que el código real que usa la matriz no se ejecuta en el ámbito del archivo, simplemente coloque la aserción en el código que accede a la matriz. Las ventajas de hacerlo son muchas: la aserción termina encapsulada junto con el código relevante, por lo que solo ese código la ve. Y no contamina el espacio de nombres global con la macro misteriosa. Además, el mensaje de error del compilador no contiene necesariamente el nombre de la variable. En mi compilador, solo obtengo algo como “expresión constante ilegal”, pero señala la línea exacta que causa el problema, por lo que realmente no es un problema.

    – Lundin

    7 de mayo de 2012 a las 9:43

  • Elegí esta respuesta porque es razonablemente fácil de agregar a mi código existente.

    – usuario694733

    10 de mayo de 2012 a las 8:44


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad