Aller au contenu | Aller au menu | Aller à la recherche

enum Vs define

Cramé pour cramé, et ayant repris une activité de blogging (oui, j'ai commencé ce billet y'a un bout de temps, juste après le SSTIC :-) ), autant pousser jusqu'au bout.....


En plus du vil et mesquin dépilage de vieux billets en attente (mais oui, ca va venir..... un jour..... surement......), ca fait quelques temps que je cherchais un sujet sympa pour un billet technique, à défaut de petits jeunes au labo pour m'en proposer de temps en temps (Jo, si tu lis cette phrase, tes pinces à tétons certifiées "CE" nous manquent ! :-) )


Le sujet du jour sera donc "enum ou defines dans un source en C", j'aurais bien fait monter le suspense méga grave, mais comme l'info était déjà dans le titre, j'ose espérer que vous vous en doutiez déjà, sinon vous risquez d'avoir du mal à lire la suite.....

T'as un problème qui te fait faire du soucis ?

Ouaip: au boulot, on se pose régulièrement la question quand on a une liste de valeurs possibles à stocker dans un int: on fait des defines ou un enum ? Et il se trouve qu'on s'est reposé aujourd'hui une question sur les enum......

Un exemple permettra presque à ma soeur de comprendre le problème, pour peu que ca soit concret.... Supposons qu'on veuille stocker dans une variable le jour de la semaine.
La solution à base de define donne ca:

#define DIMANCHE 0
#define LUNDI 1
#define MARDI 2
#define MERCREDI 3
#define JEUDI 4
#define VENDREDI 5
#define SAMEDI 6
int jourdelasemaine;

La solution à base d'enum donne ca:

enum {DIMANCHE, LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI} jourdelasemaine;

Round 1 ..... FIGHT !!!!

On voit tout de suite que la solution à base de defines a l'indéniable avantage de permettre de facturer plus de lignes de code au client, et qu'en plus elle passe mieux dans la mise en page du blog.....
Ca fait également plus technique, surtout si on se met à déclarer les valeurs en hexadécimal, ce qui donne:

#define DIMANCHE  0x0
#define LUNDI     0x1
#define MARDI     0x2
#define MERCREDI  0x3
#define JEUDI     0x4
#define VENDREDI  0x5
#define SAMEDI    0x6
int jourdelasemaine;

Alors que l'enum nous mache le travail, et va même jusqu'à commencer automatiquement la liste à 0 si on ne précise pas la première valeur.....

Bon, bah voila, je pensais qu'il serait un peu plus long que ca, ce billet, en fait.....

La prochaine fois, on parlera d'autre chose, du coup.....

Round 2 ..... FIGHT !!!!

Bon, je suis chaud bouillant comme une baraque à frites aussi vais-je rajouter l'hypothèse certes peu vraisemblable suivante: l'argent n'a pas d'odeur (en tout cas, pas beaucoup quand on est juste à coté de la baraque à frites susnommée), et on veut surtout faire un truc logique et intelligent.

En plus, par souci d'équité et de neutralité, je me dois de vous signaler qu'on peut aussi faire ca:

enum {
     DIMANCHE,
     LUNDI,
     MARDI,
     MERCREDI,
     JEUDI,
     VENDREDI,
     SAMEDI}
 jourdelasemaine;

Et donc facturer à peu près aussi cher l'implémentation à base d'enum.....

Une fois ce nouveau contexte établi, la solution à base d'enum pourrait paraitre la plus logique, en tout cas dans des langages de noobs...
Mais en C, il n'en est rien: la norme précise en effet qu'il ne s'agit que d'une facilité à l'édition, et que l'enum en question reste de toutes facons stocké dans un int.

On peut facilement le vérifier, par exemple avec le code suivant:

jourdelasemaine=SAMEDI;
printf("%d\n", jourdelasemaine);
jourdelasemaine++;
printf("%d\n", jourdelasemaine);
jourdelasemaine=42;
printf("%d\n", jourdelasemaine);

Tout ca fonctionne normalement, l'enum ne sert donc à rien par rapport à un define, si ce n'est éventuellement l'affectation automatique des valeurs (on a pas eu besoin de dire que dimanche=0, c'est implicite par défaut).... quand on a des valeurs qui se suivent, évidemment.....

Round 3 ..... FIGHT !!!!

D'un point de vue vérification de cohérence à la compilation, on est donc marrons (marron fricadelle, pour être précis), on peut faire tout et surtout n'importe quoi avec les deux approches, match NULL pour l'instant.....

Peut être à un petit détail près, qui m'a été signalé à l'instant par un stagiaire développeur du labo:

Dans le cas ou on fait un switch sans cas par défaut, si c'est un enum, le compilateur (en tout cas au moins un gcc récent) va signaler s'il manque une valeur de l'enum:

En reprenant notre enum de tout à l'heure, si on fait:

int isWE(jourdelasemaine j){
    switch(j){
        case lundi:
        case mardi:
        case jeudi:
        case vendredi:
            return 0;
            break;
        case samedi:
        case dimanche:
            return 1;
            break;
    }

}

Bah le compilateur va raler parcequ'on a oublié la valeur "mercredi"...... enfin, si on compile en -Wall Werror, mais tout le monde compile tous ses programmes comme ca, pas vrai ?

Ca suppose aussi qu'on n'utilise pas la facilité du target par defaut d'un switch, ce qui est quand même assez fréquent.......

Round 4 ..... FIGHT !!!!

Qu'en est-il de l'utilisation mémoire ?

A priori, léger avantage au define: un enum est systématiquement stocké sur un int (en tout cas, j'ai pas trouvé comment le faire tenir sur moins), alors que, dans le cas du define, on peut déclarer explicitement un short, un u_int8_t ou autre chose dans le genre qui ne prend pas trop de place quand on sait que ca va suffire pour faire tenir toutes nos valeurs possibles (et dans mon exemple, ca va tenir à l'aise), voire carrément un champ de bits si on est dans une struct et qu'on a d'autres champs de bits à poser à coté.......

Round 5 ..... FIGHT !!!!

Bon, je me foule vraiment pas en titres intermédiaires, moi, sur ce coup la......

le dernier aspect, c'est l'épépinage du code....

Et la, faut reconnaitre que l'enum a un avantage: gdb va indiquer la valeur de l'enum, alors que, avec un define, il va afficher la valeur numérique. Donc, dans le cas ou on est pas trop boulet et ou on a mis des noms explicites pour ses enum, faut admettre que ca fera gagner un peu de temps......

D'un autre coté, quand on est pas trop boulet, on n'a pas besoin de gdb, si ? :-D

And the winner is .....

Si on résume, le define est plus approprié pour grapiller quelques octets, et l'enum est plus facile pour débugguer....... dit autrement: le define, c'est pour les barbus, l'enum, c'est parfait pour les noobs qui codent avec des moufles......

La prochaine fois, on essaiera de trouver un sujet technique un peu plus poilu, quand même.......

Commentaires

1. Le lundi, novembre 8 2010, 20:14 par f

Sachant que les registres du CPU font 32 ou 64bits, il faut m'expliquer la différence entre un short et un int :-)

2. Le mardi, novembre 9 2010, 16:39 par Yvan VANHULLEBUS

La taille ?

Je sais, je suis le premier à dire que ca compte pas toujours, mais dans un struct voire dans un gros tableau, dans notre cas précis ca va avoir nettement plus d'importance que le gout.......

3. Le vendredi, décembre 10 2010, 11:10 par boblesurfeur

La conclusion de ce match n'a aucun sens :c'est l'oeuvre de quelqu'un qui rien compris a ces 2 notions!

Le "define" est remplacé lors de la précompilation : c'est l'équivalent d'un "remplacer tout" fait par l'editeur juste avant de lancer la compilation.
Il est utilisé plutot pour des constantes ou des donnes fixes qui peuvent etre amenées à changer dans une version future du code. On veut se garder la possibilité de pouvoir modifier la valeur sans rechercher toutes les occurences du code.

L'enum quand a lui est un type représentant une enumération de valeur.
On l'utilise sur une variable dont le nombre de valeurs est finie. Comme mentionné cela permet au compilateur d'interdire d'autres valeurs et ainsi de gérer une cohérence des données.

Les 2 cas meme si ils produiront un résultat similaire en fonctionnement permettent des possibilités différentes au moment du codage.
Le define permet de faire des choses impossible a l'enum et l'enum ajoute des vérifications supplémentaire a un simple define de valeur numérique.

4. Le mercredi, janvier 5 2011, 16:10 par Yvan VANHULLEBUS

Allons bon, faut maintenant que je comprenne les notions derrière les sujets sur lesquels je fais des billets, maintenant !

Bah déjà que j'en faisais plus beaucoup comme ca.......

En théorie, cher bob, tu as raison: c'est des notions qui devrait être très différentes, et on ne devrait jamais avoir à se poser la question d'utiliser l'un ou l'autre, ca devrait toujours être évident.

En pratique, c'est une question qui se pose régulièrement, et il suffit de prendre presque n'importe quel gros projet opensource au pif (ok, je bluffe surement un peu, la, mais pas beaucoup.....) pour trouver des exemples ou ils utilisent des define dans le cas que tu décris comme typique de l'enum (énumération de valeurs finies).

Et non, ca ne permet pas vraiment au compilateur de vérifier la cohérence des données, puisque la norme C autorise tout à fait de faire un enum {FAUX, VRAI} et d'affecter la valeur 42 à une variable de cet enum........

Bref, l'enum en C, ca serait bien et vraiment utile si c'était un enum comme en ADA .......

Euh ..... c'est vraiment moi qui viens d'écrire ca ???????????????

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

Fil des commentaires de ce billet