¿Existe la posibilidad de convertir los nombres de los enumeradores a cadenas en C?
De una forma, hacer que el preprocesador haga el trabajo. También asegura que sus enumeraciones y cadenas estén sincronizadas.
#define FOREACH_FRUIT(FRUIT) \
FRUIT(apple) \
FRUIT(orange) \
FRUIT(grape) \
FRUIT(banana) \
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
enum FRUIT_ENUM {
FOREACH_FRUIT(GENERATE_ENUM)
};
static const char *FRUIT_STRING[] = {
FOREACH_FRUIT(GENERATE_STRING)
};
Una vez finalizado el preprocesador, tendrá:
enum FRUIT_ENUM {
apple, orange, grape, banana,
};
static const char *FRUIT_STRING[] = {
"apple", "orange", "grape", "banana",
};
Entonces podrías hacer algo como:
printf("enum apple as a string: %s\n",FRUIT_STRING[apple]);
Si el caso de uso es simplemente imprimir el nombre de la enumeración, agregue las siguientes macros:
#define str(x) #x
#define xstr(x) str(x)
Entonces hazlo:
printf("enum apple as a string: %s\n", xstr(apple));
En este caso, puede parecer que la macro de dos niveles es superflua, sin embargo, debido a cómo funciona la cadena de caracteres en C, es necesaria en algunos casos. Por ejemplo, digamos que queremos usar un #define con una enumeración:
#define foo apple
int main() {
printf("%s\n", str(foo));
printf("%s\n", xstr(foo));
}
La salida sería:
foo
apple
Esto se debe a que str convertirá en cadena la entrada foo en lugar de expandirla para que sea apple. Al usar xstr, la expansión de la macro se realiza primero, luego ese resultado se secuencia.
Consulte Cadena de caracteres para obtener más información.
#define GENERATE_ENUM(ENUM) PREFIX##ENUM,
En una situación en la que tiene esto:
Me gusta poner esto en el archivo de encabezado donde se define la enumeración:
fuente
enumToString(apple)
que escribir"apple"
? No es que haya ningún tipo de seguridad en ninguna parte. A menos que me esté perdiendo algo, lo que sugieres aquí no tiene sentido y solo logra ofuscar el código.No hay una forma sencilla de lograr esto directamente. Pero P99 tiene macros que le permiten crear este tipo de función automáticamente:
en un archivo de encabezado, y
en una unidad de compilación (archivo .c) debería funcionar, en ese ejemplo se llamaría a la función
color_getname
.fuente
Encontré un truco del preprocesador de C que está haciendo el mismo trabajo sin declarar una cadena de matriz dedicada (Fuente: http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/c_preprocessor_applications_en ).
Enumeraciones secuenciales
Después de la invención de Stefan Ram, las enumeraciones secuenciales (sin indicar explícitamente el índice, por ejemplo
enum {foo=-1, foo1 = 1}
) se pueden realizar como este truco genial:Esto da el siguiente resultado:
Enumeraciones no secuenciales
Como quería asignar las definiciones de los códigos de error a una cadena de matriz, para poder agregar la definición de error sin procesar al código de error (por ejemplo
"The error is 3 (LC_FT_DEVICE_NOT_OPENED)."
), extendí el código de esa manera que puede determinar fácilmente el índice requerido para los respectivos valores de enumeración :En este ejemplo, el preprocesador de C generará el siguiente código :
Esto da como resultado las siguientes capacidades de implementación:
fuente
No necesita depender del preprocesador para asegurarse de que sus enumeraciones y cadenas estén sincronizadas. Para mí, el uso de macros tiende a hacer que el código sea más difícil de leer.
Usando Enum y una matriz de cadenas
Nota: las cadenas de la
fruit_str
matriz no tienen que declararse en el mismo orden que los elementos de enumeración.Cómo usarlo
Agregar una verificación de tiempo de compilación
Si tiene miedo de olvidar una cadena, puede agregar la siguiente verificación:
Se informará un error en el momento de la compilación si la cantidad de elementos de enumeración no coincide con la cantidad de cadenas de la matriz.
fuente
Una función como esa sin validar la enumeración es un poco peligrosa. Sugiero usar una declaración de cambio. Otra ventaja es que esto se puede utilizar para enumeraciones que tienen valores definidos, por ejemplo, para banderas donde los valores son 1,2,4,8,16, etc.
También coloque todas sus cadenas de enumeración juntas en una matriz: -
definir los índices en un archivo de encabezado: -
Hacer esto facilita la producción de diferentes versiones, por ejemplo, si desea hacer versiones internacionales de su programa con otros idiomas.
Usando una macro, también en el archivo de encabezado: -
Haga una función con una declaración de cambio, esto debería devolver un
const char *
porque las cadenas de caracteres estáticos const: -Si se programa con Windows, los valores ID_ pueden ser valores de recursos.
(Si usa C ++, todas las funciones pueden tener el mismo nombre.
)
fuente
Una alternativa más simple a la respuesta de "enumeraciones no secuenciales" de Hokyo, basada en el uso de designadores para instanciar la matriz de cadenas:
fuente
Yo suelo hacer esto:
fuente