1
votes

De bons cas d'utilisation pour déclarer des balises de type enum et des noms de variables en C?

Si vous avez besoin de certaines constantes dans votre code, vous pouvez les déclarer avec des énumérations:

enum animals {
    DOG,
    CAT,
    FISH,
} pets;

enum transport {
    CAR,
    BUS,
    TRAIN,
} vehicles;

puis utiliser DOG , BUS , etc. au besoin. Mais les énumérations peuvent également être déclarées dans un style plus détaillé:

enum {
    DOG,
    CAT,
    FISH,
};

enum {
    CAR,
    BUS,
    TRAIN,
};

Étant donné que les constantes enum ont une portée globale et ne peuvent pas être référencées par pets.DOG comme le peuvent les structs et les unions, y a-t-il de bons cas d'utilisation du style verbeux? Pour moi, les balises de type et les noms de variable pour les énumérations semblent assez redondants, même décevants car ils ressemblent à des structures mais ne peuvent pas être utilisés comme des structures. J'espère qu'il me manque quelque chose et qu'ils ont une bonne utilisation.

Il existe un lien SO Q&R où l'hypothèse primordiale est que l'on utiliserait les balises de type et les noms de variables lors de l'utilisation d'énumérations. Ma question peut donc être reformulée comme suit: "Dans quelles tâches échouerais-je si j'utilise uniquement des énumérations anonymes?" Parce que pour moi, le point entier des énumérations sont les constantes DOG , CAT , CAR et je ne vois aucune utilité pour en attribuer une à un variable enum. J'apprends encore, donc je suis sûr qu'il me manque quelque chose.


5 commentaires

@Ctx Veuillez clarifier! Autant que je sache et d'après mes tests, les constantes enum doivent avoir des noms uniques. Je ne comprends pas à quoi vous faites vraiment référence par "Deux énumérations ... des valeurs différentes ... des contextes différents".


Ok, avec les énumérations ce n'est en effet pas possible


Je ne suis pas sûr de bien comprendre votre question, mais la raison pour laquelle vous utiliseriez une balise enum est de pouvoir y faire référence plus tard (par exemple pour définir une variable de type enum) - ref. par exemple. Pourquoi les constantes d'énumération C ont-elles besoin d'un nom? .


Ou demandez-vous pourquoi vous définiriez des variables de type enum?


@SanderDeDycker Je demande la facilité d'utilisation des deux types et variables. Comme l'indique ma question, j'ai l'impression que les énumérations sont utiles pour les constantes qu'elles déclarent. Les constantes sont globales et doivent être uniques - alors à quoi servent le type et les variables? Une réponse complète serait grandement appréciée.


4 Réponses :


3
votes

Vous pouvez donner un nom aux types enum au cas où vous voudriez déclarer des variables de ce type:

void foo(enum animals a);

Ou les avoir comme arguments de fonction:

enum animals a1 = DOG;
enum animals a2 = CAT;

Bien que les énumérations soient considérées comme des types entiers, vous pouvez également utiliser un int pour stocker l'une de ces valeurs, en utilisant une variable d'un enum code> type aide à documenter votre code et à rendre votre intention claire pour le lecteur.


8 commentaires

OK, donc fondamentalement, je peux m'en tirer en traitant les constantes enum comme des entiers, à la fois pour les déclarations de variables et les arguments de fonction. L'utilité du type et de la variable enum réside dans leur propriété "commenting", signalant l'intention. Pas plus que ça, non?


@Theo Certains compilateurs fournissent également des avertissements utiles pour éviter les erreurs, comme par exemple enum animals a1 = TRAIN;


@ user694733 C'est intéressant, mais je suppose que j'aurais une raison d'assigner une constante d'énumération à une variable d'énumération particulière. Ma question est: pourquoi voudrais-je faire cela? Après tout, je déclare enums pour obtenir des constantes prêtes, connues par DOG , TRAIN etc. Pourquoi utiliser le type enum et les noms de variables?


@ Theod'Or: une utilisation typique d'une variable est lorsque vous ne connaissez pas la valeur au moment de la compilation (soit parce qu'elle est basée sur une entrée, soit sur un paramètre d'une fonction, soit ...). Cela est vrai pour toutes les variables, y compris les variables de type enum.


@SanderDeDycker Veuillez publier une réponse complète indiquant un échec dû à la non-utilisation du type enum et du nom de variable. Les assertions génériques sur les variables n'aident pas, en particulier lorsque le but des énumérations est qu'elles servent de constantes de temps de compilation, avec une portée globale.


@ Theod'Or: 42 est une constante de compilation de type int - cela signifie-t-il qu'il n'est pas utile d'avoir des variables de type int ? Maintenant, remplacez DOG par 42 et enum animals par int . Vous semblez confondre différents concepts et / ou mal comprendre le concept de variables. Jusqu'à ce que je comprenne où réside votre confusion, je ne peux pas publier de réponse - je ne peux que diffuser des informations qui, espérons-le, déclencheront la compréhension.


@SanderDeDycker Merci de me supporter, je l'apprécie. Je suis peut-être en train de confondre des concepts parce que les concepts sont en effet confondus. Lorsque le but de la définition des énumérations est de définir des constantes int, je les utiliserais comme ints. Je ne vois aucune raison réelle au-delà du simple affichage de l'intention d'utiliser des noms de types enum et des noms de variables. D'où ma question - y a-t-il des raisons plus fortes que la signalisation de l'intention?


@ Theod'Or: comme mentionné par @ user694733 ci-dessus, certains compilateurs produiront également des avertissements de "sécurité de type" pour les types enum lorsque vous vous trompez accidentellement. Cela peut être très utile. Si vous utilisez simplement int , vous ne les obtiendrez pas. Même sans ces avertissements, je considère qu'il est beaucoup plus clair de voir enum animals dans le code plutôt que simplement int , car alors je sais que le code est travailler avec un animal, et pas seulement avec n'importe quelle valeur entière possible. La réponse de dbush couvre cela.



2
votes

"Pour moi, les balises de type et les noms de variables pour les énumérations semblent assez redondants ..."

La valeur de l'utilisation d'une collection séquentielle de valeurs entières nommées sous la forme d'une liste énumérée ( enum ) peut sembler subtile à première vue, mais devient très évident lorsqu'il est utilisé dans des projets C pour plusieurs raisons:

  • Les noms associés à une liste énumérée fournissent code auto-documenté, c'est-à-dire en particulier lors de la collecte de noms choisi pour représenter un ensemble de valeurs énumérées forme un thème lié à la tâche à accomplir. (Votre animal enum est un bon exemple, car serait celui utilisé pour énumérer par exemple. une grande liste de commandes, ou types de poste au sein d'une entreprise.)
  • L'affectation par défaut des valeurs dans une liste énumérée est séquentiel, à partir de 0, et incrémenté de un jusqu'à la fin de la liste, résultant en une liste de valeurs uniques, très bien adaptée pour à utiliser lors de l'indexation via un tableau de chaînes avec des signification, ou lorsqu'il est utilisé dans une instruction switch en tant qu'entier constant valeur pour chacune des instructions case .

Et concernant le commentaire: "... mais l'avantage d'utiliser le type ANML au lieu de int est minime, ..."

    Les listes
  • enum fournissent également une contrainte documentée. Par exemple en utilisant ANML anml; plutôt que int anml; en tant que membre struct indiquera rapidement à ceux qui vont maintenir / mettre à jour le code source (dans les mois ou années à venir.) liste associée de valeurs liées que ce membre est contraint d'utiliser, plutôt que toute valeur entière aléatoire. Ceci est important lorsqu'une liste énumérée sera utilisé, par exemple. dans une instruction switch conçue uniquement pour gérer un ensemble d'instructions case qui correspondent aux valeurs entières constantes dans cette énumération .

Ces deux ensemble font partie du cas d'utilisation que j'ai trouvé particulièrement utile, c'est-à-dire utiliser des énumérations en conjonction avec des tableaux de chaînes pour sélectionner le contenu de l'interface utilisateur, ou pour la recherche de sous-chaînes, etc. p >

Exemple:

bool searchBuf(SEARCH *animal)
{
    bool res = FALSE;
    switch (animal->anml) {
        case CAT:
            //use the string animal[type] for a search, or user interface content, etc.
            if(strstr(animal->content, strings[CAT]))
                res = TRUE;
            break;
        case DOG:
            if(strstr(animal->content, strings[DOG]))
                res = TRUE;
            break;
        case FISH:
            if(strstr(animal->content, strings[FISH]))
                res = TRUE;
            break;
    };
    return res;
}

int main(void)
{
    char buffer[] = {"this is a string containing cat."};
    SEARCH search;
    strcpy(search.content, buffer);
    search.anml = CAT;

    bool res = searchBuf(&search);
    //use res...

    return 0;    
}

Où, par exemple, les deux constructions peuvent alors être utilisées en conjonction avec une instruction switch :

typedef enum {
       CAT,
       DOG,
       FISH,
       MAX_ANML
    }ANML;//for use in struct

 char *strings[MAX_ANML] = {"cat","dog","fish"};

    typedef struct {
        char content[80];
        ANML anml;
    }SEARCH;


2 commentaires

Merci, ça a l'air très bien et utile, mais votre code ne se compile pas. En outre, utilisez-vous le type enum et les noms de variables?


@ryyker Votre code est très utile pour montrer comment une recherche peut être construite, mais l'avantage d'utiliser le type ANML au lieu de int est minime: le nom anml du membre struct rend l'intention suffisamment claire. J'ai maintenant posté ma propre réponse et j'attendrai quelque chose de plus convaincant.



0
votes

J'aime les énumérations au lieu de #defines lorsque je débogue. Le debuer me montre non seulement la valeur numérique, mais aussi le nom d'énumération - très pratique


1 commentaires

Par «enum name», faites-vous référence à la constante d'énumération telle que DOG dans mon exemple, ou au nom d'une variable d'énumération à laquelle la constante peut être affectée?



0
votes

Je publie ma propre réponse après qu'un certain nombre d'autres personnes aient publié des réponses et des commentaires utiles, et nous sommes allés jusqu'à établir que les noms de types enum et les noms de variables sont utiles en tant que code auto-documenté et que l'intention du code soit claire ( grâce aux réponses de ryyker et dbush).

Alors que j'expérimentais et recherchais des raisons plus solides d'utiliser des énumérations non anonymes, j'ai établi qu'il ne peut pas y en avoir par définition. Les énumérations n'ont pas de vérification de portée et de limites, ni au moment de la compilation (GCC 6) ni au moment de l'exécution. Voici un extrait de code démontrant la faiblesse:

enum withType { // enum with type name and variable name
    ONE,
    TWO,
    THREE,
} wtEnum;

enum { // Anonymous enum
    TINY,
    SMALL,
    MID,
    LARGE,
    BIGGEST,
};

int main(void) {
    enum withType wt1 = LARGE; // Overflow!
    wtEnum = BIGGEST; // Overflow!
    printf("Enum test values: %d, %d, %d\n", THREE, wt1, wtEnum);
    return 0;
};

L'exemple montre clairement que toute "portée" que vous voudrez peut-être faire avec les noms de type enum et les noms de variable est uniquement par convention, et repose sur la discipline du codeur pour ne pas croiser les «domaines» d'énumération. J'irais jusqu'à affirmer que compte tenu de cette réalité, la fonctionnalité d'énumération en C est "mal conçue". Cela crée l'impression du type d'utilité que nous voyons avec les structures et les unions, mais ne fournit rien de tel. Après cet aperçu, je considère que les énumérations anonymes sont les seules énumérations sûres à utiliser!

Tout cela dit, j'ai accepté la réponse de ryyker car elle fournit une belle démonstration de l'utilisation courante des énumérations. Mais je laisse ma propre réponse ici aussi, car les points que j'ai soulevés sont valables.


7 commentaires

J'inclus généralement toujours une préface MAX_ à la dernière valeur d'une liste énumérée, faisant de la valeur de cette dernière valeur == le nombre de valeurs de la liste. Je fais cela en particulier lorsque je prévois de l'utiliser pour créer un ensemble (tableau) de chaînes correspondant à chaque valeur enum de l'ensemble. (Vous avez peut-être remarqué cela dans l'exemple de code de ma réponse


Les deux instances que vous avez montrées avec les commentaires // Overflow! , en plus d'être des cas d'utilisation très improbables, illustrent des instances où l'avertissement du compilateur aurait dû être quelque chose à l'effet: warning: integer constant not in plage de type énuméré 'enum with Type' . Ce qui, étant donné le but général du type enum est un avertissement très approprié et utile. Comme cela a été indiqué à plusieurs endroits autour de cet article, Créer une plage de valeurs constantes entières, avec noms , généralement d'un thème, fournit 1) un code auto-documenté et 2) un moyen de ...


... énumérer un ensemble limité de critères, d'attributs, de chemins d'exécution, etc.


@ryyker En utilisant le // Overflow! Je voulais démontrer le manque de portée des énumérations, une constante enum peut être assignée à n'importe quelle énumération. Je n'ai pas reçu l'avertissement que vous avez mentionné, mais j'ai utilisé uniquement -Wall . Je vais examiner les autres options pour activer l'avertissement.


Si vous y réfléchissez, veuillez poster vos résultats et me taguer dans un commentaire. La plupart des bons compilateurs (gcc inclus) avertiront de cette utilisation.


@ryyker J'ai vérifié la page de manuel de GCC et il n'y a pas d'options pour l'avertissement. Le plus proche est fsanitize = enum , mais cela fait partie des options d'instrumentation d'exécution qui provoqueraient une erreur d'exécution, pas un avertissement de compilation. Vous faisiez peut-être référence à un autre compilateur. Il convient également de noter dans la page de manuel que C ++ 11 a des énumérations de portée, exactement ce que C devrait avoir. J'essaierai de contacter Jens Gustedt qui est actif sur SO et qui fait également partie du groupe de travail standard C pour poser des questions sur la possibilité de scoping enums dans C.


Mon erreur sur GCC , et je suis surpris. Je l'utilise souvent, mais toujours en conjonction avec des compilateurs CLANG et NI. L'avertissement que j'ai cité ci-dessus (2ème commentaire) est une reproduction exacte de ce que CLANG a produit. Un avertissement similaire est produit lorsque j'utilise le compilateur standard de National Instruments, avec les extensions d'extensions C99 activées. (Et j'ai vérifié ces deux derniers il y a à peine quelques minutes :))