Question

J'ai déjà lu cette question connexe , mais je cherchais quelque chose d'un peu plus spécifique.

  • Existe-t-il un moyen d'indiquer précisément à votre compilateur la largeur de votre énumération?
  • Si oui, comment procédez-vous?Je sais comment le spécifier en C #;est-ce fait de la même manière en C?
  • Cela en vaudrait-il même la peine?Lorsque la valeur d'énumération est passée à une fonction, sera-t-elle passée sous la forme d'une valeur de la taille d'un int?
Était-ce utile?

La solution

Existe-t-il un moyen de dire à votre compilateur spécifiquement la largeur que vous voulez de votre enum être?

Dans le cas général no. Pas dans la norme C.

Cela vaudrait-il même la peine d'être fait?

Cela dépend du contexte. Si vous parlez de passer des paramètres aux fonctions, alors non, cela ne vaut pas la peine (voir ci-dessous). S'il s'agit d'économiser de la mémoire lors de la création d'agrégats à partir de types enum, cela peut valoir la peine. Cependant, en C, vous pouvez simplement utiliser un type entier de taille appropriée au lieu d'un type enum dans les agrégats. En C (par opposition à C ++), les types énumération et les types entiers sont presque toujours interchangeables.

Lorsque la valeur d'énumération est passée à une fonction, sera-t-elle passée sous forme de valeur de taille int malgré tout?

De nos jours, de nombreux (la plupart) des compilateurs transmettent tous les paramètres comme des valeurs de taille de mot naturelle pour la plate-forme matérielle donnée. Par exemple, sur une plate-forme 64 bits, de nombreux compilateurs transmettront tous les paramètres sous forme de valeurs 64 bits, quelle que soit leur taille réelle, même si le type int contient 32 bits sur cette plate-forme (donc, il n'est généralement pas passé comme "int -size "valeur sur une telle plateforme). Pour cette raison, cela n'a aucun sens d'essayer d'optimiser les tailles d'énumération à des fins de passage de paramètres.

Autres conseils

Je pense qu'il existe un indicateur si vous utilisez GCC.

-fshort-enums

Vous pouvez le forcer à avoir au moins une certaine taille en définissant une valeur appropriée.Par exemple, si vous voulez que votre énumération soit stockée avec la même taille qu'un int, même si toutes les valeurs tiendraient dans un char, vous pouvez faire quelque chose comme ceci:

typedef enum {
    firstValue = 1,
    secondValue = 2,

    Internal_ForceMyEnumIntSize = MAX_INT
} MyEnum;

Notez cependant que le comportement peut dépendre de l'implémentation.

Comme vous le notez, passer une telle valeur à une fonction entraînera son expansion en un int de toute façon, mais si vous utilisez votre type dans un tableau ou une structure, alors la taille importera.Si vous vous souciez vraiment de la taille des éléments, vous devriez vraiment utiliser des types comme int8_t, int32_t, etc.

Il existe également un autre moyen si l'énumération fait partie d'une structure:

struct something {
     :0;
   enum whatever field:CHAR_BIT;
     :0;
};

Le: 0;peut être omis si le champ enum est entouré de champs normaux.S'il y a un autre champ de bits avant, le: 0 forcera l'alignement d'octet sur l'octet suivant pour le champ qui le suit.

Cela dépend des valeurs attribuées aux énumérations.

Ex: Si la valeur supérieure à 2 ^ 32-1 est stockée, la taille allouée pour l'énumération globale passera à la taille suivante.

Stockez la valeur 0xFFFFFFFFFFFF dans une variable d'énumération, cela donnera un avertissement si vous essayez de compiler dans un environnement 32 bits (avertissement arrondi) Où, comme dans une compilation 64 bits, elle réussira et la taille allouée sera de 8 octets.

Comme @ Nyx0uf dit , GCC a un indicateur que vous pouvez définir:

-fshort-enums

Allouez à un type enum uniquement autant d'octets que nécessaire pour la plage déclarée de valeurs possibles. Plus précisément, le type enum est équivalent au plus petit type entier disposant de suffisamment d'espace.

Attention: le commutateur -fshort-enums amène GCC à générer du code qui n'est pas compatible binaire avec le code généré sans ce commutateur. Utilisez-le pour vous conformer à une interface binaire d'application autre que celle par défaut.

Source: https://gcc.gnu.org/onlinedocs /gcc/Code-Gen-Options.html

Lectures intéressantes supplémentaires pour des informations générales: https://www.embedded.fm/blog/2016/6/28/how-big-is-an-enum .
Intéressant ... remarquez la ligne que j'ai surlignée en jaune ci-dessous!

 entrez la description de l'image ici

Dans certaines circonstances, cela peut être utile:

typedef uint8_t command_t;
enum command_enum
{
    CMD_IDENT                = 0x00,     //!< Identify command
    CMD_SCENE_0              = 0x10,     //!< Recall Scene 0 command
    CMD_SCENE_1              = 0x11,     //!< Recall Scene 1 command
    CMD_SCENE_2              = 0x12,     //!< Recall Scene 2 command
};

/* cmdVariable is of size 8 */
command_t cmdVariable = CMD_IDENT; 

D'une part, le type command_t a la taille 8 et peut être utilisé pour le type de paramètre de variable et de fonction. D'un autre côté, vous pouvez utiliser les valeurs d'énumération pour l'assignation qui sont de type int par défaut mais le compilateur les convertira immédiatement lorsqu'il est assigné à une variable de type command_t.

De plus, si vous faites quelque chose de dangereux comme définir et utiliser un CMD_16bit = 0xFFFF,, le compilateur vous avertira avec le message suivant:

avertissement: grand entier implicitement tronqué en type non signé [-Woverflow]

Même si vous écrivez un code C strict, les résultats dépendront du compilateur.En utilisant les stratégies de ce fil, j'ai obtenu des résultats intéressants ...

< enum_size.c

#include <stdio.h>

enum __attribute__((__packed__)) PackedFlags {
    PACKED = 0b00000001,
};

enum UnpackedFlags {
    UNPACKED = 0b00000001,
};

int main (int argc, char * argv[]) {
  printf("packed:\t\t%lu\n", sizeof(PACKED));
  printf("unpacked:\t%lu\n", sizeof(UNPACKED));
  return 0;
}
$ gcc enum_size.c
$ ./a.out
packed:         4
unpacked:       4
$ gcc enum_size.c -fshort_enums
$ ./a.out
packed:         4
unpacked:       4
$ g++ enum_size.c
$ ./a.out
packed:         1
unpacked:       4
$ g++ enum_size.c -fshort_enums
$ ./a.out
packed:         1
unpacked:       1

Dans mon exemple ci-dessus, je n'ai réalisé aucun avantage du modificateur __attribute__((__packed__)) avant de commencer à utiliser le compilateur C ++.

< EDIT:

Les soupçons de @ technosaurus étaient justes.

En vérifiant la taille de sizeof(enum PackedFlags) au lieu de sizeof(PACKED), je vois les résultats attendus ...

  printf("packed:\t\t%lu\n", sizeof(enum PackedFlags));
  printf("unpacked:\t%lu\n", sizeof(enum UnpackedFlags));

Je vois maintenant les résultats attendus de gcc:

$ gcc enum_size.c
$ ./a.out
packed:         1
unpacked:       4
$ gcc enum_size.c -fshort_enums
$ ./a.out
packed:         1
unpacked:       1

Une autre méthode consiste à transtyper l'énumération dans une union comme suit:

union char_size {
  char a;
  enum {
    a = 1,
    b = 2,
  } val;
};

Cela forcera le compilateur à insérer l'énumération dans un caractère.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top