Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Différence entre #define et enum

39 réponses
Avatar
Vincent Belaïche
Bonjour,

Dans la Foire à Questions du groupe on trouve
http://www.levenez.com/lang/c/faq/fclc006.html#q_8

6.8 Quelle est la différence entre une énumération et des #define ?

Il y a peu de différences.

L'un des avantages de l'énumération est que les valeurs numériques sont
assignées automatiquement. De plus, une énumération se manipule comme un
type de données. Certains programmeurs reprochent aux énumérations de
réduire le contrôle qu'ils ont sur la taille des variables de type
énumération.


Il me semble qu'il y a d'autres différences notables:

1) avec les #define on peut tester une valeur entière pendant le
prétraitement

#define TOTO 1

#if TOTO == 1
...
#elif TOTO == 2
...
#else
#endif

(même si le code ci-dessus peut ne pas plaire pour diverse raison, c'est
très utilisé)
Le code ci-dessus ne marche pas si TOTO est un enum

2) Les enum sont en général dispo sous forme symbolique dans un
débogueur qui se respecte, pas les #define

3) Par rapport au commentaire sur la taille non controllée avec les
énum, il me semble qu'on peut qualifier un enum avec `: taille_en_bit'
au sein d'un typedef, un peu comme les champ d'une structure. À
vérifier, et aussi à quelle norme ça répond.

Vincent.

10 réponses

1 2 3 4
Avatar
Samuel DEVULDER
Antoine Leca a écrit :
Samuel DEVULDER écrivit :
Mais qu'est ce qui dit que l'enum est unsigned? Mystère!



Si tu fabriques des membres d'une énumération qui ont des valeurs plus
grandes que INT_MAX (32767 en 16 bits, cela va vite), de toutes façons



Les états d'une machines à états par exemple.

tu es dans le royaume des extensions propriétaires.



Tu parles du support d'un enum avec plus de INT_MAX constantes (enum
{A0, A1, ..., A32767, A32768}), ou le fait qu'une constante dépasse
INT_MAX (enum {A=0, B2768}) ?

Maintenant, si ton implémentation décide de son propre chef de rendre
non signé (retypé en unsigned voire unsigned long) une constante
d'énumération alors même que sa valeur est inférieure à INT_MAX, c'est
une non-conformité en bonne et due forme.



Est-ce que je comprends bien ce que tu dis en disant que ce sont les
constantes de l'enum qui sont signed/unsigned et pas le type lui même?
enum {LUNDI, MARDI, MERCREDI=3u, JEUDI, ...}. Le MERCREDI est unsigned,
mais pas MARDI ou JEUDI?

Je sens que ca n'est pas cela, si?

Plus généralement, je me demande s'il n'aurait pas été préférable que
les enums soient des trucs purement opaques et symboliques, sans valeur
numérique ou du moins sans possibilité de faire de l'arithmétique .. Une
sorte de #define "structuré" en gros.

En effet, je ne comprends pas bien ce qu'est l'utilité de faire des
calculs sur des constantes numériques. Est-ce bien raisonnable de ne pas
avoir d'erreurs sur "t_jour a, b; a=MARDI; b=2*a-JEUDI;" ? qu'est ce
qu'on peut bien chercher à faire avec des symboles dans un expression
artihmétique?!? Les histoires de signed/unsigned dérivent de là aussi je
pense.

sam.
Avatar
Antoine Leca
Samuel DEVULDER a écrit :
Antoine Leca a écrit :
Samuel DEVULDER écrivit :
Mais qu'est ce qui dit que l'enum est unsigned? Mystère!



Si tu fabriques des membres d'une énumération qui ont des valeurs plus
grandes que INT_MAX (32767 en 16 bits, cela va vite), de toutes façons
tu es dans le royaume des extensions propriétaires.



Tu parles du support d'un enum avec plus de INT_MAX constantes (enum
{A0, A1, ..., A32767, A32768}), ou le fait qu'une constante dépasse
INT_MAX (enum {A=0, B2768}) ?



Le second, enum {A=INT_MAX, B, C};


Maintenant, si ton implémentation décide de son propre chef de rendre
non signé (retypé en unsigned voire unsigned long) une constante
d'énumération alors même que sa valeur est inférieure à INT_MAX, c'est
une non-conformité en bonne et due forme.



Est-ce que je comprends bien ce que tu dis en disant que ce sont les
constantes de l'enum qui sont signed/unsigned et pas le type lui même?



Le type (c'est quoi en fait ?) est une énumération, et on s'en moque la
plupart du temps. Les membres de l'énumération créent automatiquement
des constantes de même nom, qui sont des int avec la valeur sous-jacente.
Sauf extension du compilateur qui permet d'avoir autre chose que int.


enum {LUNDI, MARDI, MERCREDI=3u, JEUDI, ...}. Le MERCREDI est unsigned,
mais pas MARDI ou JEUDI?



MERCREDI est signé en C normal (et vaut 3, 2 de plus que MARDI).
C'est parfaitement comparable à
const int Mercredi = 3u;
const signed char Samedi = 7ul;
Tant Mercredi comme Samedi ont des valeurs signées.


Plus généralement, je me demande s'il n'aurait pas été préférable que
les enums soient des trucs purement opaques et symboliques, sans valeur
numérique ou du moins sans possibilité de faire de l'arithmétique ..



Il est des fois où tu as besoin quand même de faire de l'arithmétique.
Par exemple, en C le jour qui suit MERCREDI s'écrit MERCREDI+1, pas
MERCREDI'SUCC. Par contre ni MERCREDI*2 ni JAUNE+1 n'ont de sens.
MARCH_31ST/2 n'a pas non plus de sens, mais PLUVIOSE10/30 si. Etc.


Antoine
Avatar
Manuel Pégourié-Gonnard
Jean-Marc Bourguet scripsit :

Manuel Pégourié-Gonnard writes:

Vincent Belaïche scripsit :

------------------------
enum couleurs {
rouge, vert, bleu
};
typedef char couleurs;
------------------------



Juste pour être sûr : ce code est valide en C, mais pas en C++, non ?



Exact. En gros en C++ il y un typedef automatique

typedef struct/union/enum t t;

avec des exceptions pour autoriser

struct stat;

int stat();

mais la forme ci-dessus ne relève pas des exceptions.



Ok, merci.

--
Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu
http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
Avatar
Manuel Pégourié-Gonnard
Antoine Leca scripsit :

Le type (c'est quoi en fait ?) est une énumération, et on s'en moque la
plupart du temps. Les membres de l'énumération créent automatiquement
des constantes de même nom, qui sont des int avec la valeur sous-jacente.
Sauf extension du compilateur qui permet d'avoir autre chose que int.

enum {LUNDI, MARDI, MERCREDI=3u, JEUDI, ...}. Le MERCREDI est unsigned,
mais pas MARDI ou JEUDI?



MERCREDI est signé en C normal (et vaut 3, 2 de plus que MARDI).
C'est parfaitement comparable à
const int Mercredi = 3u;
const signed char Samedi = 7ul;
Tant Mercredi comme Samedi ont des valeurs signées.



En fait, est-il exact de dire que les deux fragments de code suivants
sont équivalents ?

typedef enum {
a = 1,
b,
} foo;

et

const int a = 1;
const int b = 2;
typedef const int foo;

--
Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu
http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
Avatar
Richard Delorme
Le 08/04/2010 23:47, Manuel Pégourié-Gonnard a écrit :
Antoine Leca scripsit :

Le type (c'est quoi en fait ?) est une énumération, et on s'en moque la
plupart du temps. Les membres de l'énumération créent automatiquement
des constantes de même nom, qui sont des int avec la valeur sous-jacente.
Sauf extension du compilateur qui permet d'avoir autre chose que int.

enum {LUNDI, MARDI, MERCREDI=3u, JEUDI, ...}. Le MERCREDI est unsigned,
mais pas MARDI ou JEUDI?



MERCREDI est signé en C normal (et vaut 3, 2 de plus que MARDI).
C'est parfaitement comparable à
const int Mercredi = 3u;
const signed char Samedi = 7ul;
Tant Mercredi comme Samedi ont des valeurs signées.



En fait, est-il exact de dire que les deux fragments de code suivants
sont équivalents ?



Non.


typedef enum {
a = 1,
b,
} foo;



Ici a et b n'ont pas d'adresses.

const int a = 1;
const int b = 2;
typedef const int foo;



Ici ils en ont une.

--
Richard
Avatar
Manuel Pégourié-Gonnard
Manuel Pégourié-Gonnard scripsit :

En fait, est-il exact de dire que les deux fragments de code suivants
sont équivalents ?

typedef enum {
a = 1,
b,
} foo;

et

const int a = 1;
const int b = 2;
typedef const int foo;



Bon, je me réponds : non, ce n'est pas exact, dans le second cas,
l'expression &a est légale, pas dans le premier.

Y a-t-il d'autres différences ? Mes recherches sur le grand Nain ne
semblent donner de réponses que concernant le C++ pour cette question.

--
Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu
http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
Avatar
Samuel DEVULDER
Manuel Pégourié-Gonnard a écrit :

En fait, est-il exact de dire que les deux fragments de code suivants
sont équivalents ?

typedef enum {
a = 1,
b,
} foo;

et

const int a = 1;
const int b = 2;
typedef const int foo;




Je dirais que non. "const int a" occupe une certaine place mémoire, on
peut récupérer son adresse. En revanche le symbole "a" de l'enum en
typedef n'occupe aucune place mémoire et on ne peut d'ailleurs récupérer
son adresse (tout comme si on avait utilisé un #define").

sam.
Avatar
Samuel DEVULDER
Antoine Leca a écrit :

Le type (c'est quoi en fait ?) est une énumération, et on s'en moque la
plupart du temps. Les membres de l'énumération créent automatiquement
des constantes de même nom, qui sont des int avec la valeur sous-jacente.
Sauf extension du compilateur qui permet d'avoir autre chose que int.


enum {LUNDI, MARDI, MERCREDI=3u, JEUDI, ...}. Le MERCREDI est unsigned,
mais pas MARDI ou JEUDI?



MERCREDI est signé en C normal (et vaut 3, 2 de plus que MARDI).



Ah ok.. Pourtant le compilo HP dit que les enums sont "unsigned int" sur
64bits et "signed int" en 32. Si sizeof(int)=4, et sizeof(long)=8, avec:
enum {A=0xffffffff} a = A; long b = a;
on devrait avoir b = 0xffffffff ffffffff en 32bits et
0x00000000 ffffffff en 64?
Ca fait bizarre. C'est peut-être une extension non standard le fait
qu'ils considèrent les enums en unsigned sous 64bits. Je sais pas.


C'est parfaitement comparable à
const int Mercredi = 3u;
const signed char Samedi = 7ul;
Tant Mercredi comme Samedi ont des valeurs signées.



Oui il y a conversion: signed char samedi = 0x80ul, écrit (signed
char)0x80ul = -128 dans samedi en fait.

Plus généralement, je me demande s'il n'aurait pas été préférable que
les enums soient des trucs purement opaques et symboliques, sans valeur
numérique ou du moins sans possibilité de faire de l'arithmétique ..



Il est des fois où tu as besoin quand même de faire de l'arithmétique.
Par exemple, en C le jour qui suit MERCREDI s'écrit MERCREDI+1, pas
MERCREDI'SUCC. Par contre ni MERCREDI*2 ni JAUNE+1 n'ont de sens.
MARCH_31ST/2 n'a pas non plus de sens, mais PLUVIOSE10/30 si. Etc.



Ouais.. Ca dépend du cas par cas. Cela dit je trouve PLUVIOSITE10/30
bizarre. On dirait qu'on utilise un enum comme un nombre standard.
Pourquoi ne pas dans ce cas utiliser directement un type entier plutôt
qu'un enum? Et si on ne veut pas d'un entier parce que ca ne documente
pas quelle sens donner à la valeur (2°c, c'est pas pareil que 2mm
d'eau), pourquoi ne pas faire "typedef int PLUVIOSITE /* en mm d'eau */;
" dans le code?

Merci,

sam.
Avatar
Antoine Leca
Samuel DEVULDER écrivit :
Ah ok.. Pourtant le compilo HP dit que les enums sont "unsigned int" sur
64bits



Quelle idée bizarre.
Autrement dit, avec un tel compilateur :

enum jours jour;
/* ... */
/* recule dans la semaine jusqu'au week end */
while( --jour >= 0 ) /*...*/

donne un résultat différent suivant la taille des entiers...
J'ai pas dit que c'était bô :-) mais c'est en tous cas quelque chose qui
va fonctionner sur la plupart des machines... sauf ce compilo-ci.



Ca dépend du cas par cas. Cela dit je trouve PLUVIOSITE10/30 bizarre.



C'est PLUVIOSE10 / 30. PLUVIOSE10 représentant le 10 pluviôse (en C on
ne peut pas commencer par un chiffre). Et le calendrier révolutionnaire
avait des mois tous de 30 jours, donc l'expression ci-dessus donne le
mois, ici pluviôse. De même, en divisant par 10 tu obtiens la «dimaine»,
l'équivalent de la semaine. Toutes chose que que tu ne peux pas faire
avec le calendrier grégorien, en tous cas pas aussi facilement
(je connais Zeller).
Bref, c'est une anecdote. Si on revenais au C ?


Antoine
Avatar
Jean-Marc Bourguet
Manuel Pégourié-Gonnard writes:

Antoine Leca scripsit :

Le type (c'est quoi en fait ?) est une énumération, et on s'en moque la
plupart du temps. Les membres de l'énumération créent automatiquement
des constantes de même nom, qui sont des int avec la valeur sous-jacente.
Sauf extension du compilateur qui permet d'avoir autre chose que int.

enum {LUNDI, MARDI, MERCREDI=3u, JEUDI, ...}. Le MERCREDI est unsigned,
mais pas MARDI ou JEUDI?



MERCREDI est signé en C normal (et vaut 3, 2 de plus que MARDI).
C'est parfaitement comparable à
const int Mercredi = 3u;
const signed char Samedi = 7ul;
Tant Mercredi comme Samedi ont des valeurs signées.



En fait, est-il exact de dire que les deux fragments de code suivants
sont équivalents ?

typedef enum {
a = 1,
b,
} foo;

et

const int a = 1;
const int b = 2;
typedef const int foo;



Certainement pas avec un const.

La différence pratique la plus importante que je vois est que a et b dans
le second cas ne peuvent pas être utilisés dans les expressions entières
constantes.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
1 2 3 4