vectores programacion matrices lenguaje imprimir ejemplos caracteres cadenas cadena bidimensionales arreglos arreglo c arrays switch-statement

programacion - matrices en lenguaje c



¿Hay alguna forma de usar una matriz constante con índice constante como etiqueta de caja de interruptor en C? (6)

El motivo del error es simplemente que C no considera const int LABEL_A=0; ser una constante en tiempo de compilación. Desafortunadamente, así es como se define el idioma. Se puede resolver usando #define LABEL_A 0 lugar.

Una tercera alternativa es usar enumeraciones, que podrían ser mejores, ya que podrían usarse para unir todos sus datos y proporcionar un poco más de integridad de datos durante el mantenimiento:

typedef enum { LABEL_A, LABEL_B, LABEL_C, LABEL_D, LABELS_N } label_index_t; typedef void func_t (void); typedef struct { const char* str; int hash; func_t* func; } value_t; ... const value_t VALUE [] = { [LABEL_A] = { .str = "LABEL_A", .hash = 67490, .func = a_func }, [LABEL_B] = { .str = "LABEL_B", .hash = 67491, .func = b_func }, [LABEL_C] = { .str = "LABEL_C", .hash = 67493, .func = c_func }, [LABEL_D] = { .str = "LABEL_D", .hash = 67459, .func = d_func }, }; _Static_assert(sizeof VALUE / sizeof *VALUE == LABELS_N, "Size of VALUE does not match label_t."); ... // instead of switch(n): VALUE[n].func();

Tengo algunos valores constantes y matrices que definen sus etiquetas y sus códigos hash. Por ejemplo,

#define LABEL_A 0 //or const int LABEL_A = 0; #define LABEL_B 1 #define LABEL_C 2 #define LABEL_D 3 const char *VALUE[] = {"LABEL_A", "LABEL_B", "LABEL_C", "LABEL_D"}; const int VALUE_HASH[] = {67490, 67491, 67493, 67459);

En tiempo de ejecución, estas etiquetas pueden venir en cualquier orden y deben analizarse en consecuencia. Estoy usando la caja del interruptor para este propósito. Este código está generando un error en el tiempo de compilación "se requiere expresión constante.

function(const char* LabelAtRuntime){ int i = getHashCode(LabelAtRuntime); switch(i){ case VALUE_HASH[LABEL_A]: //line giving compile time error break; default: break; }

Pero, cuando proporciono constantes reales, funciona. Este código funciona bien.

function(const char* LabelAtRuntime){ int i = getHashCode(LabelAtRuntime); switch(i){ case 67490: //line not giving compile time error break; default: break; }

  1. No puedo entender, ¿por qué está sucediendo? Tanto mi matriz como su índice son constantes, ¿entonces no es equivalente a un literal constante?
  2. ¿Hay alguna otra manera por la cual pueda proporcionar mis constantes de la manera requerida?

Estoy usando constantes de esta manera para proporcionar una mejor semántica de código, legibilidad y reutilización. No proporcione if-else solución basada en if-else . En el ejemplo anterior, solo hay 4 etiquetas, pero en la práctica, podría haber 100.


En C ++, esto compila:

#include <stdio.h> #include <stdlib.h> constexpr int x[] = { 42, 43 }; int main(int argc, char **argv) { switch(atoi(argv[1])) { case x[0]: puts("forty_two"); break; case x[1]: puts("forty_three"); } return 0; }

Por constexpr tanto, constexpr en la matriz parece ser la solución en C ++ moderno. (Nota: la pregunta fue originalmente etiquetada C ++ y C)

Es imposible en C si quieres mantener la matriz. Los casos de cambio requieren una constante entera , pero una vez que se pone un entero constante en una variable, se convierte en una entidad en tiempo de ejecución (incluso si se declara const). Lo que podría hacer es reemplazar la matriz en memoria con solo un grupo de definiciones directas y posiblemente tener una macro que busque macros usando otras macros (si desea conservar su forma del código):

#define LABEL_A 0 #define LABEL_B 1 #define LABEL_C 2 #define LABEL_D 2 #define VALUE_HASH__0 67490 #define VALUE_HASH__2 67491 #define VALUE_HASH__3 67491 #define VALUE_HASH__4 64759 //append what Index expands to to VALUE_HASH__ #define HASH_LOOKUP(Index) MC_cat(VALUE_HASH__,Index) #define MC_cat_(X,Y) X##Y #define MC_cat(X,Y) MC_cat_(X,Y) function(const char* LabelAtRuntime){ int i = getHashCode(LabelAtRuntime); switch(i){ case HASH_LOOKUP(LABEL_A) break; default: break; }


La caja del interruptor requiere que los valores se conozcan en el tiempo de compilación. En su caso de valores de matriz, los valores no se conocen hasta el tiempo de ejecución.

Si está utilizando c ++ 11, podría usar constexpr que obliga al compilador a evaluar los valores de la matriz en tiempo de compilación. El siguiente código funciona bien.

constexpr int VALUE_HASH[] = {67490, 67491, 67493, 67459}; int i = getHashCode(LabelAtRuntime); switch(i) { case VALUE_HASH[LABEL_A]: break; default: break; }


No es suficiente que los operandos sean constantes. No es suficiente que se los conozca en tiempo de compilación (sea lo que sea lo que signifique, el estándar C no habla en estos términos). La etiqueta de la caja debe ser una expresión constante entera .

Las expresiones constantes enteras están definidas rigurosamente por el estándar C. Aproximadamente, una expresión constante entera debe construirse a partir de constantes enteras (también enumeradores, constantes de caracteres y similares) y no puede contener matrices o punteros, incluso si son constantes. Para una explicación más accesible pero a la vez vea por ejemplo esto .


No sé lo que realmente estás haciendo. Pero cuando tuve que implementar una interfaz de usuario de menú en C, lo hice así:

// Typedef for a menu item''s logic function (callback): typedef void (*menu_item_cb_t)(void*) // Struct defining a menu item: typedef struct menu_item { const char* label; const int hashValue; const menu_item_cb_t callback; const void* callback_arg; } menu_item_t; // Callback for menu item "Do X": void menu_do_x( void* arg ) { // ... } // Definition of menu item "Do X": const menu_item_t menu_item_x = { "Do X", 12345, &menu_do_x, NULL // Don''t need it to do x } // All menu items go into one array: const menu_item_t* MENU[] = { &menu_item_x, ...}; #define MENU_ITEM_CNT xxx

Entonces puedes actuar sobre el elemento seleccionado como:

void menuItemSelected( const char* label ) { const int hash = getHashCode(label); for ( int i = 0; i < MENU_ITEM_CNT; i++ ) { const menu_item_t* const mi = MENU[i]; if ( hash == mi->hash ) { mi->callback( mi->callback_arg ); break; } } }

Este enfoque puede ser variado, pero espero que entiendas la idea. Básicamente es solo para definir elementos con ciertas propiedades ("etiqueta", "hash" y cualquier otra cosa) y asociarlos directamente con la función que implementa la acción correspondiente para este elemento.


Si VALUE_HASH solo se usa para obtener las constantes del interruptor, ¿por qué no reemplazarlo con una tabla de salto?

Tenga en cuenta que ninguno de los siguientes está probado o incluso compilado. Puede haber errores de sintaxis.

Primero defina un tipo para las funciones en la tabla:

typedef void (*Callback)(/* parameters you need */);

Entonces necesitas tus funciones reales

void labelAProcessing(/* the parameters as per the typedef */) { /// processing for label A } // etc

Entonces tu mesa

Callback valueCallbacks[] = { labelAProcessing, labelBProcessing, ... };

Y tu código se convierte

int i = getHashCode(LabelAtRuntime); valueCallbacks[i](/* arguments */);

No puedo enfatizar demasiado que necesito ser validado para asegurarme de que sea un índice válido para la matriz valueCallbacks ya que de lo contrario, podría llamar a un número aleatorio como si fuera una función.