¿El tamaño de (enumeración) == tamaño de (int), siempre?

11 minutos de lectura

avatar de usuario
Vivek Sharma

¿El tamaño de (enum) == tamaño de (int), siempre?

  • ¿O depende del compilador?
  • ¿Está mal decir que el compilador está optimizado para longitudes de palabra (alineación de memoria), es decir, y int es el tamaño de palabra en un compilador en particular? ¿Significa que no hay penalización de procesamiento si uso enumeraciones, ya que estarían alineados con las palabras?
  • ¿No es mejor si pongo todos los códigos de devolución en una enumeración, ya que claramente no me preocupo por los valores que obtiene, solo los nombres mientras verifico los tipos de devolución? Si este es el caso, #DEFINE no será mejor ya que ahorraría memoria.

¿Cuál es la práctica habitual? Si tengo que transportar estos tipos de devolución a través de una red y se debe realizar algún procesamiento en el otro extremo, ¿qué preferiría enums/#defines/ const ints.

EDITAR: solo verifico en la red, ya que el compilador no vincula simbólicamente las macros, ¿cómo depuran las personas entonces, comparan el valor entero con el archivo de encabezado?

De Respuestas —Agrego esta línea a continuación, ya que necesito aclaraciones—

“Así que está definido por la implementación y sizeof(enum) puede ser igual al tamaño de (char), es decir, 1″.

  • ¿No significa que el compilador verifica el rango de valores en las enumeraciones y luego asigna memoria? No lo creo, por supuesto que no lo sé. ¿Puede alguien explicarme qué es “podría ser”.

  • Consulta: stackoverflow.com/questions/366017/… Y esto: bytes.com/groups/cpp/135139-sizeof-enum-sizeof-int

    – Macarse

    11 de julio de 2009 a las 14:49

  • De net- en algún foro, “Pensé que se suponía que una enumeración era tan pequeña como fuera necesario para contener todos sus valores, en este caso 1 byte”. Es verdad.

    – Vivek Sharma

    11 de julio de 2009 a las 14:50

  • Gracias a todo, estoy aprendiendo algunas dudas razonables, lo que creo que seguramente ayudará a mejorar el concepto.

    – Vivek Sharma

    11 de julio de 2009 a las 15:02

  • Encontré las respuestas de “nuriaion” y “lulian Sebaniou” relevantes para una parte de la pregunta. Alguien ps comentario sobre la corrección.

    – Vivek Sharma

    11 de julio de 2009 a las 15:09

  • Posible duplicado de ¿Cuál es el tamaño de una enumeración en C?

    – subrayado_d

    16/09/2018 a las 16:31

avatar de usuario
Johannes Schaub – litb

Depende del compilador y puede diferir entre enumeraciones. Las siguientes son las semánticas.

enum X { A, B };

// A has type int
assert(sizeof(A) == sizeof(int));

// some integer type. Maybe even int. This is
// implementation defined. 
assert(sizeof(enum X) == sizeof(some_integer_type));

Tenga en cuenta que “algún tipo de entero” en C99 también puede incluir tipos de enteros extendidos (que la implementación, sin embargo, tiene que documentar, si los proporciona). El tipo de enumeración es algún tipo que puede almacenar el valor de cualquier enumerador (A y B en este caso).

No creo que haya penalizaciones en el uso de enumeraciones. Los enumeradores también son expresiones constantes integrales (por lo que puede usarlos para inicializar variables estáticas o de alcance de archivo, por ejemplo), y los prefiero a las macros siempre que sea posible.

Los enumeradores no necesitan ninguna memoria de tiempo de ejecución. Solo cuando crea una variable del tipo de enumeración, puede usar la memoria de tiempo de ejecución. Solo piense en los enumeradores como constantes de tiempo de compilación.

Simplemente usaría un tipo que pueda almacenar los valores del enumerador (debo conocer el rango aproximado de valores de antemano), transmitirlo y enviarlo a través de la red. Preferiblemente, el tipo debe ser de ancho fijo, como int32_t, por lo que no se producen conflictos cuando se trata de diferentes máquinas. O imprimiría el número y lo escanearía en el otro lado, lo que elimina algunos de estos problemas.


Respuesta a editar

Bueno, no se requiere que el compilador use ningún tamaño. Una cosa fácil de ver es que el signo de los valores es importante: los tipos sin firmar pueden tener un aumento significativo del rendimiento en algunos cálculos. El siguiente es el comportamiento de GCC 4.4.0 en mi caja

int main(void) {
  enum X { A = 0 };
  enum X a; // X compatible with "unsigned int"
  unsigned int *p = &a;
}

Pero si asignas un -1entonces GCC elige usar int como el tipo que X es compatible con

int main(void) {
  enum X { A = -1 };
  enum X a; // X compatible with "int"
  int *p = &a;
}

Usando la opción --short-enums de GCC, que hace que use el tipo más pequeño que aún se ajuste a todos los valores.

int main() {
  enum X { A = 0 };
  enum X a; // X compatible with "unsigned char"
  unsigned char *p = &a;
}

En versiones recientes de GCC, el indicador del compilador ha cambiado a -fshort-enums. En algunos objetivos, el tipo predeterminado es unsigned int. Puedes comprobar la respuesta aquí.

  • Creo que ahora, en lugar de almacenar cada comando en una variable char sin firmar y equipararlo a un valor, lo almacenaré en #define, como siempre se ha hecho. Las enumeraciones enfrentarán problemas de orden de bytes. Creo que ahora entiendo por qué #define siempre se ha usado para códigos de error, nombres de estado, comandos… etc.

    – Vivek Sharma

    11 de julio de 2009 a las 16:53

  • No es completamente cierto que no hay diferencia entre enumeraciones y #defines: como dijiste para #defines, el compilador ni siquiera ve el token inicial, ya que el preprocesador lo sustituye por el valor real. Sin embargo, el compilador ve las enumeraciones, y si compila el código con símbolos de depuración, el depurador le mostrará las etiquetas enumeradas en lugar de su valor, lo que ayuda enormemente a la depuración.

    – Metiú

    12 de julio de 2009 a las 23:27

  • Toda esta charla sobre #define’s… Si alguien más está leyendo esto, tómelo de un gurú que lo último que quiere hacer es usar #define’s en C++ para constantes/enumeraciones. No estoy agregando cómo y qué más usar en un comentario, pero no es de #define.

    – Carlos Wood

    1 de febrero de 2019 a las 20:43

  • en la respuesta, no está claro qué se entiende por “lo siguiente es la semántica”. ¿Está afirmando que las afirmaciones son siempre verdaderas?

    – xdavidliu

    7 dic 2019 a las 16:47

C99, 6.7.2.2p4 dice

Cada tipo enumerado será compatible con char, un tipo entero con signo o un tipo entero sin signo. La elección del tipo está definida por la implementación, 108) pero debe ser capaz de representar los valores de todos los miembros de la enumeración. […]

La nota al pie 108 agrega

Una implementación puede retrasar la elección de qué tipo de entero hasta que se hayan visto todas las constantes de enumeración.

Por lo tanto, está definido por la implementación y sizeof(enum) podría ser igual a sizeof(char), es decir, 1.

Al elegir el tamaño de un rango pequeño de números enteros, hay siempre una falta. Si lo hace pequeño en la memoria, probablemente haya una penalización de procesamiento; si lo haces más grande, hay una penalización de espacio. Es un intercambio espacio-tiempo.

Los códigos de error suelen ser #defines, porque deben ser extensibles: diferentes bibliotecas pueden agregar nuevos códigos de error. No puedes hacer eso con enumeraciones.

  • ¿No significa que el compilador verifica el rango de valores en las enumeraciones y luego asigna memoria? No lo creo, por supuesto que no lo sé :). ¿Pueden algunos explicar qué es “podría ser”?

    – Vivek Sharma

    11 de julio de 2009 a las 15:04

  • “El compilador hace” es una declaración inútil. Hay muchos compiladores en el mundo, y algunos lo hacen de una manera y otros lo hacen de otra manera (incluso en el mismo hardware). Si desea saber qué hace un compilador específico, debe nombrar el compilador (incluida la versión y la CPU y el sistema operativo de destino). bien puede ser que tu el compilador siempre usa int para las enumeraciones.

    – Martin contra Löwis

    11 de julio de 2009 a las 15:57

  • La segunda respuesta aquí da una versión diferente del mismo estándar donde dice que debe ser compatible con int. ¿Su versión está desactualizada (él enlaza a un borrador) o la tuya?

    – Norswap

    13/10/2012 a las 22:57

  • @Norswap Creo que esa respuesta es una mala interpretación del (mismo) estándar.

    usuario824425

    18 de febrero de 2016 a las 17:47

¿Es el tamaño de (enum) == tamaño de (int), siempre

El estándar ANSI C dice:

Cada tipo enumerado será compatible con char, un tipo entero con signo o un tipo entero sin signo. La elección del tipo está definida por la implementación. (6.7.2.2 Especificadores de enumeración)

Así que tomaría eso como que no.

Si este es el caso, #DEFINE no será mejor ya que ahorraría memoria.

¿De qué manera el uso de defines ahorraría memoria sobre el uso de una enumeración? Una enumeración es solo un tipo que le permite proporcionar más información al compilador. En el ejecutable resultante real, simplemente se convierte en un número entero, al igual que el preprocesador convierte una macro creada con #definir en su valor.

Cuál es la práctica habitual. Si tengo que transportar estos tipos de devolución a través de una red y se debe realizar algún procesamiento en el otro extremo

Si planea transportar valores a través de una red y procesarlos en el otro extremo, debe definir un protocolo. Decida el tamaño en bits de cada tipo, el estado final (en qué orden están los bytes) y asegúrese de cumplirlo tanto en el código del cliente como en el del servidor. Además, no asumas que porque resulta que funciona, lo has hecho bien. Es posible que, por ejemplo, la endianess de las plataformas de servidor y cliente elegidas coincida, pero puede que no siempre sea así.

  • sí, esa es la preocupación, he transferido algún valor para usar como comando en la red, y deseo que sea lo más eficiente y robusto posible, es decir, necesito opiniones sobre qué usar para el comando #defines o enumeraciones, el rango de comandos no serán más de 20 comandos, por lo que de acuerdo con todo en el límite de caracteres. Creo que lo publicaré como una nueva pregunta. Obtendría una mejor respuesta.

    – Vivek Sharma

    11 de julio de 2009 a las 15:13

  • Entonces, lo más fácil sería simplemente usar un carácter sin firmar. No tiene que preocuparse por la endianess o la codificación de esa manera.

    – IRBMe

    11 de julio de 2009 a las 15:22

  • tal vez podría agregar una referencia a ¿Debería usar cstdint? para la sección de red

    – Lobo

    13 de septiembre de 2017 a las 9:18


No.

Ejemplo: El compilador CodeSourcery

Cuando defines una enumeración como esta:

enum MyEnum1 {
A=1,
B=2,
C=3
};
// will have the sizeof 1 (fits in a char)

enum MyEnum1 {
A=1,
B=2,
C=3,
D=400
};
// will have the sizeof 2 (doesn't fit in a char)

Detalles de su lista de correo

avatar de usuario
nuriaion

En algunos compiladores, el tamaño de una enumeración depende de cuántas entradas haya en la enumeración. (menos de 255 entradas => Byte, más de 255 entradas int) Pero esto depende del compilador y de la configuración del compilador.

  • hay alguna forma puedo forzar esto. Un buen aporte gracias sin embargo.

    – Vivek Sharma

    11 de julio de 2009 a las 15:03

  • Debido a estos problemas en nuestro proyecto (tenemos que usar un compilador de C realmente antiguo), decidimos no usar enum. Pero para definir todo con #define

    – nuriaión

    14 de julio de 2009 a las 20:02

  • No se trata de la cantidad de miembros del enumerador, sino del rango de valores que representan. podría tener un enum que contiene 2 miembros: {apples = 0, oranges = 1000}. ¿Crees que el compilador puede encajarlos en cualquier char (“Byte”)? No sin tener un mapeo entre los valores del enumerador y los valores subyacentes, que obviamente no existe: eso sería una pesadilla para la implementación, el rendimiento y el uso. Un enum es realmente solo una forma de tener algún tipo de entero sensible al contexto pero poder referirse a sus miembros con identificadores textuales; los miembros se almacenan como sus valores numéricos.

    – subrayado_d

    16 de septiembre de 2018 a las 16:28


avatar de usuario
marcelo pacheco

enum fruits {apple,orange,strawberry,grapefruit};  
char fruit = apple;  
fruit = orange;  
if (fruit < strawberry)  
...  

todo esto funciona perfectamente
si desea un tipo subyacente específico para una instancia de enumeración, simplemente no use el tipo en sí.

  • hay alguna forma puedo forzar esto. Un buen aporte gracias sin embargo.

    – Vivek Sharma

    11 de julio de 2009 a las 15:03

  • Debido a estos problemas en nuestro proyecto (tenemos que usar un compilador de C realmente antiguo), decidimos no usar enum. Pero para definir todo con #define

    – nuriaión

    14 de julio de 2009 a las 20:02

  • No se trata de la cantidad de miembros del enumerador, sino del rango de valores que representan. podría tener un enum que contiene 2 miembros: {apples = 0, oranges = 1000}. ¿Crees que el compilador puede encajarlos en cualquier char (“Byte”)? No sin tener un mapeo entre los valores del enumerador y los valores subyacentes, que obviamente no existe: eso sería una pesadilla para la implementación, el rendimiento y el uso. Un enum es realmente solo una forma de tener algún tipo de entero sensible al contexto pero poder referirse a sus miembros con identificadores textuales; los miembros se almacenan como sus valores numéricos.

    – subrayado_d

    16 de septiembre de 2018 a las 16:28


¿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