2010-08-11 18 views
7

¿Hay alguna manera de mostrar el nombre del valor de una enumeración? decir que tenemos:Método genérico para mostrar nombres de valores enum

enum fuits{ 
    APPLE, 
    MANGO, 
    ORANGE, 
}; 

main(){ 
enum fruits xFruit = MANGO; 
... 
printf("%s",_PRINT_ENUM_STRING(xFruit)); 
... 
} 

usando el preprocesador

#define _PRINT_ENUM_STRING(x) #x 

no funcionará, ya que necesitamos para obtener el valor de la variable 'x' y luego convertirlo a cadena. ¿Esto es posible en c/C++?

+0

posible duplicado http://stackoverflow.com/questions/3342726/c-print-out-enum-value-as-text –

+1

Esto es un FAQ todo sobre los intertubes y probablemente sea un imbécil aquí, aunque no lo hice. Respuesta: no, no se puede hacer (sin jumoing a través de aros como @Naveen sugiere y corre el riesgo de desconectarse. Si está dispuesto a correr ese riesgo, muchas personas parecen usar esta solución. Es mejor que nada , pero es un destino tentador ...). – Mawg

+0

@Eugen Constantin Dinca Esa pregunta es solo C++, mientras que el OP aquí parece querer una solución C. – schot

Respuesta

7

podría utilizar el preprocesador para hacer esto, creo que esta técnica se llama X-Macros:

/* fruits.def */ 
X(APPLE) 
X(MANGO) 
X(ORANGE) 

/* file.c */ 
enum fruits { 
#define X(a) a, 
#include "fruits.def" 
#undef X 
}; 

const char *fruit_name[] = { 
#define X(a) #a, 
#include "fruits.def" 
#undef X 
}; 

Tenga en cuenta que la última entrada incluye una coma final, que se deja en C99 (pero no en C89). Si eso es un problema, puede agregar valores sentinales. También es posible hacer que la macro más complicado, dando múltiples argumentos para los nombres personalizados o valores de enumeración, etc:

X(APPLE, Apple, 2) 
#define X(a,b,c) a = c,  /* in enum */ 
#define X(a,b,c) [c] = #b,  /* in name array */ 

Limitaciones: No se puede tener constantes negativas y la matriz es sizeof (char *) * largest_constant. Pero se puede evitar tanto mediante el uso de una tabla de consulta adicional:

int map[] = { 
#define X(a,b,c) c, 
#include "fruits.def" 
#undef X 
}; 

Esto no funciona, por supuesto. Lo que funciona es la generación de un sistema adicional de enum constantes como claves para los nombres:

enum fruits { 
#define X(a,b,c) a ## _KEY, 
#include "fruits.def" 
#undef X 
#define X(a,b,c) a = c, 
#include "fruits.def" 
#undef X 
}; 

ya se puede encontrar el nombre de X(PINEAPPLE, Pineapple, -40) utilizando fruit_name[PINEAPPLE_KEY].

Las personas notaron que no les gustaba el archivo adicional de inclusión. No necesita este archivo adicional, también utiliza un #define. Esto puede ser más apropiada para pequeñas listas:

#define FRUIT_LIST X(APPLE) X(ORANGE) 

y reemplazar #include "fruits.def con FRUIT_LIST en los ejemplos anteriores.

+0

Esta es la mejor manera que conozco. Utilicé una técnica similar para cadenas de error con una macro X de 2 argumentos: 'X (nombre, desc)' donde la macro se expandió al código de error (análoga a valores 'errno') o una cadena descriptiva dependiendo de dónde el archivo de lista de errores fue incluido. –

+1

+1. Esto casi supera mi truco habitual de definir la enumeración en una secuencia de comandos perl que escribe la enumeración en un archivo .h y la matriz de traducción correspondiente en un archivo .c. Mi camino requiere un paso de compilación personalizado que es fácil con make, pero más difícil en un IDE completo. – RBerteig

+0

No me gusta. Puede ser útil a veces, pero no abusaría de eso. Tal vez lo usaría para enums grandes y frecuentemente cambiados. Los costos de esto son demasiado grandes. – adf88

1

Puede utilizar una asignación en este caso.

char *a[10] = { "APPLE","MANGO","ORANGE"}; 

printf("%s",a[xFruit]); 

Sí, el preprocesador no funcionará a menos que proporcione el enum-valor exacto.

También verifique this question para obtener más información.

0

he utilizado con éxito la programación preprocesador para conseguir una macro de este tipo:

DEFINE_ENUM(Fruits, (Apple)(Mango)(Orange)); 

Se hace un poco más que la impresión de los nombres, pero podría ser fácilmente simplifica a 2 interruptores si es necesario.

Se basa en las instalaciones de Boost.Preprocessor (notablemente BOOST_PP_SEQ_FOREACH) que es imprescindible para la programación del preprocesador, y me parece mucho más elegante que la instalación X y su sistema de reincorporación de archivos.

-1

 public enum LDGoalProgressUpdateState 
    {

[Description("Yet To Start")] 
    YetToStart = 1, 
    [Description("In Progress")] 
    InProgress = 2, 
    [Description("Completed")] 
    Completed = 3 
} 


    var values = (ENUMList[])Enum.GetValues(typeof(ENUMList)); 
    var query = from name in values 
       select new EnumData//EnumData is a Modal or Entity 
       { 
        ID = (short)name, 
        Name = GetEnumDescription(name)//Description of Particular Enum Name 
       }; 
    return query.ToList(); 

HelperMethods región

public static string GetEnumDescription(Enum value) { FieldInfo fi = value.GetType().GetField(value.ToString()); DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); if (attributes != null && attributes.Length > 0) return attributes[0].Description; else return value.ToString(); } #endregion
+0

Esto no parece ser C o C++ como se solicitó en la pregunta – jcoder

+0

Este código es relativo a C# –

Cuestiones relacionadas