Estoy confundido acerca de cuándo usar macros o enumeraciones. Ambos se pueden usar como constantes, pero ¿cuál es la diferencia entre ellos y cuál es la ventaja de cualquiera de ellos? ¿Está relacionado de alguna manera con el nivel del compilador o no?
¿Qué hace una mejor constante en C, una macro o una enumeración?
Varun Changani
Serguéi Kalinichenko
En términos de legibilidad, las enumeraciones son mejores constantes que las macros, porque los valores relacionados se agrupan. Además, enum
define un nuevo tipo, por lo que a los lectores de su programa les resultará más fácil averiguar qué se puede pasar al parámetro correspondiente.
Comparar
#define UNKNOWN 0
#define SUNDAY 1
#define MONDAY 2
#define TUESDAY 3
...
#define SATURDAY 7
para
typedef enum {
UNKNOWN,
SUNDAY,
MONDAY,
TUESDAY,
...
SATURDAY,
} Weekday;
Es mucho más fácil leer código como este.
void calendar_set_weekday(Weekday wd);
que esto
void calendar_set_weekday(int wd);
porque sabe qué constantes está bien pasar.
-
De hecho, pero uno podría quedarse igualmente con las macros, y luego
typedef int Weekday;
como ni typedefs ni enums son typesafe (en este sentido) en C…–Oliver Charlesworth
15 de junio de 2013 a las 16:14
-
@H2CO3: En
gdb
Yo suelop (int)Thursday
op (Weekday)3
.– jxh
15 de junio de 2013 a las 16:21
-
@varunchhangani Me gusta
enum foo { BAR = 3, BAZ = 1 << 9 }
? sí–Kevin
15 de junio de 2013 a las 18:51
-
Por cierto, es legal tener una coma después del último elemento en la lista de enumeración, por lo que el extraño formato de coma no es necesario.
– jamesdlin
15 de junio de 2013 a las 18:57
-
@jamesdlin Recientemente descubrí que era no legal en ANSI C. Me sorprendió (siempre pensé que la principal ventaja era que facilitaba un poco la generación de código), pero ahí lo tienen.
– Tomás
18 de junio de 2014 a las 7:09
Una macro es una cosa del preprocesador, y el código compilado no tiene idea de los identificadores que crea. Ya han sido reemplazados por el preprocesador antes de que el código llegue al compilador. Una enumeración es una entidad de tiempo de compilación y el código compilado retiene información completa sobre el símbolo, que está disponible en el depurador (y otras herramientas).
Prefiere enumeraciones (cuando puedas).
-
Creo que enum es más cómodo en comparación con macro en caso de depuración.
– Varun Changani
15 de junio de 2013 a las 18:47
-
No discutiendo, pero con
gcc -g3
puede compilar un ejecutable compatible con gdb que conserve información sobre las macros.– Braden Mejor
29 de septiembre de 2015 a las 0:41
Kaz
En C, es mejor usar enumeraciones para enumeraciones reales: cuando alguna variable puede contener uno de múltiples valores a los que se les puede dar nombres. Una ventaja de las enumeraciones es que el compilador puede realizar algunas comprobaciones más allá de lo que requiere el lenguaje, como que no falte una declaración de cambio en el tipo de enumeración en uno de los casos. Los identificadores de enumeración también se propagan en la información de depuración. En un depurador, puede ver el nombre del identificador como el valor de una variable de enumeración, en lugar de solo el valor numérico.
Las enumeraciones se pueden usar solo por el efecto secundario de crear constantes simbólicas de tipo integral. Por ejemplo:
enum { buffer_size = 4096 }; /* we don't care about the type */
esta práctica no está tan extendida. Por una cosa, buffer_size
se utilizará como un número entero y no como un tipo enumerado. Un depurador no renderizará 4096
dentro buffer_size
, porque ese valor no se representará como el tipo enumerado. Si declara algunos char array[max_buffer_size];
luego sizeof array
no aparecerá como buffer_size
. En esta situación, la constante de enumeración desaparece en tiempo de compilación, por lo que bien podría ser una macro. Y hay desventajas, como no poder controlar su tipo exacto. (Puede haber alguna pequeña ventaja en alguna situación en la que la salida de las etapas de preprocesamiento de la traducción se captura como texto. Una macro se habrá convertido en 4096, mientras que buffer_size
se quedará como buffer_size
).
Un símbolo de preprocesador nos permite hacer esto:
#define buffer_size 0L /* buffer_size is a long int */
Tenga en cuenta que varios valores de C <limits.h>
me gusta UINT_MAX
son símbolos de preprocesador y no símbolos de enumeración, por buenas razones, porque esos identificadores deben tener un tipo determinado con precisión. Otra ventaja de un símbolo de preprocesador es que podemos probar su presencia, o incluso tomar decisiones basadas en su valor:
#if ULONG_MAX > UINT_MAX
/* unsigned long is wider than unsigned int */
#endif
Por supuesto, también podemos probar las constantes enumeradas, pero no de tal manera que podamos cambiar las declaraciones globales en función del resultado.
Las enumeraciones tampoco son adecuadas para las máscaras de bits:
enum modem_control { mc_dsr = 0x1, mc_dtr = 0x2, mc_rts = 0x4, ... }
simplemente no tiene sentido porque cuando los valores se combinan con un OR bit a bit, producen un valor que está fuera del tipo. Dicho código también causa un dolor de cabeza, si alguna vez se transfiere a C++, que tiene (algo más) enumeraciones de tipo seguro.
-
¿Podemos cambiar el valor de enumeración en tiempo de compilación y const es igual a enumeración o macro?
– Varun Changani
15 de junio de 2013 a las 18:53
Jens
Tenga en cuenta que existen algunas diferencias entre las macros y las enumeraciones, y cualquiera de estas propiedades puede hacerlas (no) adecuadas como una constante particular.
- las enumeraciones están firmadas (compatibles con int). En cualquier contexto donde se requiere un tipo sin firmar (¡piense especialmente en operaciones bit a bit!), las enumeraciones están descartadas.
- si long long es más ancho que int, las constantes grandes no caben en una enumeración.
- El tamaño de una enumeración es (generalmente)
sizeof(int)
. Para arreglos de valores pequeños (hasta decir,CHAR_MAX
) es posible que desee unchar foo[]
en lugar de unenum foo[]
formación. - las enumeraciones son números enteros. no puedes tener
enum funny_number { PI=3.14, E=2.71 }
. - las enumeraciones son una característica de C89; Los compiladores de K&R (ciertamente antiguos) no los entienden.
Hormiga
Si macro se implementa correctamente (es decir, no sufre problemas de asociatividad cuando se sustituye), entonces no hay mucha diferencia en la aplicabilidad entre macro y constantes de enumeración en situaciones en las que ambas cosas son aplicables, es decir, en una situación en la que necesita constantes enteras con signo específicamente.
Sin embargo, en general, las macros de casos proporcionan una funcionalidad mucho más flexible. Las enumeraciones imponen un tipo específico a sus constantes: tendrán tipo int
(o, posiblemente, un tipo de entero con signo más grande), y siempre estarán firmados. Con las macros, puede usar sintaxis constante, sufijos y/o conversiones de tipo explícitas para producir una constante de cualquier tipo.
Las enumeraciones funcionan mejor cuando tiene un grupo de constantes enteras secuenciales estrechamente asociadas. Funcionan especialmente bien cuando no le importan en absoluto los valores reales de las constantes, es decir, cuando solo le importa que tengan algunos valores únicos de buen comportamiento. En todos los demás casos, las macros son una mejor opción (o básicamente la única opción).
Como cuestión práctica, hay poca diferencia. Son igualmente utilizables como constantes en sus programas. Algunos pueden preferir uno u otro por razones estilísticas, pero no puedo pensar en ninguna razón técnica para preferir uno sobre el otro.
Una diferencia es que las macros le permiten controlar el tipo integral de las constantes relacionadas. Pero un enum
utilizará un int
.
#define X 100L
enum { Y = 100L };
printf("%ld\n", X);
printf("%d\n", Y); /* Y has int type */
tarde
enum
tiene una ventaja: alcance del bloque:
{ enum { E = 12 }; }
{ enum { E = 13 }; }
Con las macros es necesario #undef
.
-
me gustaría Nunca considere dar un
enum
escriba diferentes valores en diferentes lugares en el mismo código base cualquier tipo de “ventaja” de cualquier manera o forma.–Andrew Henle
21 de febrero a las 12:00
-
Si A ofrece una característica, mientras que B no lo hace, por lo general A tiene una ventaja sobre B.
– pmor
22 de febrero a las 18:23
-
También puede dejar caer una bola de bolos en su pie. Eso no es una ventaja.
–Andrew Henle
22 de febrero a las 18:27
Creo que esta es una gran pregunta cuando la consideras así: ¿Cuáles son las diferencias entre usar macros y enumeraciones para definir constantes en C?
– Sam Harwell
15 de junio de 2013 a las 16:10