Comment choisir entre une définition de macro ou une définition de
variable avec le qualificateur const ? J'ai bien lu la réponse 5.4 de la
FAQ, et je vois bien pourquoi « ça n'a rien à voir », sauf que je
n'arrive pas à percevoir en quoi ça doit influencer le choix entre les
deux dans la pratique.
Par exemple, il me semble qu'on voit couramment des définitions comme
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Antoine Leca
Le 08/05/2009 11:56, mpg écrivit :
Comment choisir entre une définition de macro ou une définition de variable avec le qualificateur const ?
En 2009, le conseil normal, c'est de préférer const (lorsque c'est possible).
Là où cela risque de poser le plus de difficultés, c'est pour les constantes entières (genre le debug.h de ton exemple), et il y a de grandes chances que tu sois obligé d'utiliser des valeurs du pré-processeur (#define), surtout pour les dimensions de tableaux.
Avantages des #defines: le programme résultant sera plus rapide (surtout pour les vieux compilateurs), et n'utilisera pas d'espace mémoire inutile pour les constantes numériques. C'est aussi plus facile à utiliser, car il n'est pas besoin de se préoccuper des initialisations multiples (ce qui est un souci si ta constante apparaît dans plusieurs unités sans être déclarée static.)
Avantages des const : tu peux contrôler la visibilité et la portée de l'objet introduit de la même manière que pour les variables etc., car en fait c'est exactement cela, une variable (const en C signifie «readonly» bien plus que constante); et les constantes apparaissent nominativement dans le débogueur.
Est-ce que ça dépend du type (entier, chaîne) de la constante ?
Oui. Comme en C une chaîne est un tableau (voir l'autre fil à propos de printf), donc manipulée comme un pointeur, elle ne se comporte pas comme une constante numérique ; d'un autre côté, certaines constructions du C utilisent des constantes entières comme dimensions, et on ne peut alors utiliser une variable, même marquée const, comme valeur de cette constante.
Ce qui est quand même très laid de mon point de vue, mais moi je suis complètement imbibé d'un style qui n'est plus moderne...
1º err_malloc n'est PAS une constante... il est parfaitement possible d'écrire dans un autre coin du programme : err_malloc = "tout va bien, billg aux commandes"; err_realloc = "mauvaise utilisation de strtol"; même si je ne pense pas que ce soit l'effet escompté...
2º techniquement ce code a un comportement indéfini (et d'ailleurs, un compilateur normal va probablement râler) : la déclaration dans erreurs.h annonce que la chaîne est modifiable, et le compilateur peut prendre avantage de cette information, par exemple en supposant que la chaîne est allouée dans l'espace réservé aux chaînes modifiables ; mais la définition de erreurs.c va dans l'autre sens, et spécifie que les contenus des chaînes ne sont pas modifiables, donc le même compilateur devrait les alloués ailleurs, peut-être en mémoire en lecture seule (ROM)...
3º rien à l'utilisation ne permet de remarquer que err_malloc est une chaîne constante ; c'est très différent d'utiliser ERR_MALLOC, ou mieux encore MSGERR_MALLOC (ou MsgErr_malloc, si tu préfères un style plus discret et qui ne permet pas de croire qu'il s'agisse d'une valeur du pré-processeur).
Antoine
Le 08/05/2009 11:56, mpg écrivit :
Comment choisir entre une définition de macro ou une définition de
variable avec le qualificateur const ?
En 2009, le conseil normal, c'est de préférer const (lorsque c'est
possible).
Là où cela risque de poser le plus de difficultés, c'est pour les
constantes entières (genre le debug.h de ton exemple), et il y a de
grandes chances que tu sois obligé d'utiliser des valeurs du
pré-processeur (#define), surtout pour les dimensions de tableaux.
Avantages des #defines: le programme résultant sera plus rapide (surtout
pour les vieux compilateurs), et n'utilisera pas d'espace mémoire
inutile pour les constantes numériques. C'est aussi plus facile à
utiliser, car il n'est pas besoin de se préoccuper des initialisations
multiples (ce qui est un souci si ta constante apparaît dans plusieurs
unités sans être déclarée static.)
Avantages des const : tu peux contrôler la visibilité et la portée de
l'objet introduit de la même manière que pour les variables etc., car en
fait c'est exactement cela, une variable (const en C signifie «readonly»
bien plus que constante); et les constantes apparaissent nominativement
dans le débogueur.
Est-ce que ça dépend du type (entier, chaîne) de la constante ?
Oui. Comme en C une chaîne est un tableau (voir l'autre fil à propos de
printf), donc manipulée comme un pointeur, elle ne se comporte pas comme
une constante numérique ; d'un autre côté, certaines constructions du C
utilisent des constantes entières comme dimensions, et on ne peut alors
utiliser une variable, même marquée const, comme valeur de cette constante.
Ce qui est quand même très laid de mon point de vue, mais moi je suis
complètement imbibé d'un style qui n'est plus moderne...
1º err_malloc n'est PAS une constante... il est parfaitement possible
d'écrire dans un autre coin du programme :
err_malloc = "tout va bien, billg aux commandes";
err_realloc = "mauvaise utilisation de strtol";
même si je ne pense pas que ce soit l'effet escompté...
2º techniquement ce code a un comportement indéfini (et d'ailleurs, un
compilateur normal va probablement râler) : la déclaration dans
erreurs.h annonce que la chaîne est modifiable, et le compilateur peut
prendre avantage de cette information, par exemple en supposant que la
chaîne est allouée dans l'espace réservé aux chaînes modifiables ; mais
la définition de erreurs.c va dans l'autre sens, et spécifie que les
contenus des chaînes ne sont pas modifiables, donc le même compilateur
devrait les alloués ailleurs, peut-être en mémoire en lecture seule (ROM)...
3º rien à l'utilisation ne permet de remarquer que err_malloc est une
chaîne constante ; c'est très différent d'utiliser ERR_MALLOC, ou mieux
encore MSGERR_MALLOC (ou MsgErr_malloc, si tu préfères un style plus
discret et qui ne permet pas de croire qu'il s'agisse d'une valeur du
pré-processeur).
Comment choisir entre une définition de macro ou une définition de variable avec le qualificateur const ?
En 2009, le conseil normal, c'est de préférer const (lorsque c'est possible).
Là où cela risque de poser le plus de difficultés, c'est pour les constantes entières (genre le debug.h de ton exemple), et il y a de grandes chances que tu sois obligé d'utiliser des valeurs du pré-processeur (#define), surtout pour les dimensions de tableaux.
Avantages des #defines: le programme résultant sera plus rapide (surtout pour les vieux compilateurs), et n'utilisera pas d'espace mémoire inutile pour les constantes numériques. C'est aussi plus facile à utiliser, car il n'est pas besoin de se préoccuper des initialisations multiples (ce qui est un souci si ta constante apparaît dans plusieurs unités sans être déclarée static.)
Avantages des const : tu peux contrôler la visibilité et la portée de l'objet introduit de la même manière que pour les variables etc., car en fait c'est exactement cela, une variable (const en C signifie «readonly» bien plus que constante); et les constantes apparaissent nominativement dans le débogueur.
Est-ce que ça dépend du type (entier, chaîne) de la constante ?
Oui. Comme en C une chaîne est un tableau (voir l'autre fil à propos de printf), donc manipulée comme un pointeur, elle ne se comporte pas comme une constante numérique ; d'un autre côté, certaines constructions du C utilisent des constantes entières comme dimensions, et on ne peut alors utiliser une variable, même marquée const, comme valeur de cette constante.
Ce qui est quand même très laid de mon point de vue, mais moi je suis complètement imbibé d'un style qui n'est plus moderne...
1º err_malloc n'est PAS une constante... il est parfaitement possible d'écrire dans un autre coin du programme : err_malloc = "tout va bien, billg aux commandes"; err_realloc = "mauvaise utilisation de strtol"; même si je ne pense pas que ce soit l'effet escompté...
2º techniquement ce code a un comportement indéfini (et d'ailleurs, un compilateur normal va probablement râler) : la déclaration dans erreurs.h annonce que la chaîne est modifiable, et le compilateur peut prendre avantage de cette information, par exemple en supposant que la chaîne est allouée dans l'espace réservé aux chaînes modifiables ; mais la définition de erreurs.c va dans l'autre sens, et spécifie que les contenus des chaînes ne sont pas modifiables, donc le même compilateur devrait les alloués ailleurs, peut-être en mémoire en lecture seule (ROM)...
3º rien à l'utilisation ne permet de remarquer que err_malloc est une chaîne constante ; c'est très différent d'utiliser ERR_MALLOC, ou mieux encore MSGERR_MALLOC (ou MsgErr_malloc, si tu préfères un style plus discret et qui ne permet pas de croire qu'il s'agisse d'une valeur du pré-processeur).
Antoine
mpg
Antoine Leca scripsit:
Le 08/05/2009 11:56, mpg écrivit :
Comment choisir entre une définition de macro ou une définition de variable avec le qualificateur const ?
En 2009, le conseil normal, c'est de préférer const (lorsque c'est possible).
Ok.
Là où cela risque de poser le plus de difficultés, c'est pour les constantes entières (genre le debug.h de ton exemple), et il y a de grandes chances que tu sois obligé d'utiliser des valeurs du pré-processeur (#define), surtout pour les dimensions de tableaux.
Ce qui est quand même très laid de mon point de vue, mais moi je suis complètement imbibé d'un style qui n'est plus moderne...
1º err_malloc n'est PAS une constante... il est parfaitement possible d'écrire dans un autre coin du programme : err_malloc = "tout va bien, billg aux commandes"; err_realloc = "mauvaise utilisation de strtol"; même si je ne pense pas que ce soit l'effet escompté...
2º techniquement ce code a un comportement indéfini (et d'ailleurs, un compilateur normal va probablement râler) : la déclaration dans erreurs.h annonce que la chaîne est modifiable, et le compilateur peut prendre avantage de cette information, par exemple en supposant que la chaîne est allouée dans l'espace réservé aux chaînes modifiables ; mais la définition de erreurs.c va dans l'autre sens, et spécifie que les contenus des chaînes ne sont pas modifiables, donc le même compilateur devrait les alloués ailleurs, peut-être en mémoire en lecture seule (ROM)...
Donc en remplaçant par
extern const char * const err_malloc;
ça devient correct ? Ceci dit, c'est vrai que c'est un peu plus lourd syntaxiquement qu'un define, comme ça.
3º rien à l'utilisation ne permet de remarquer que err_malloc est une chaîne constante ; c'est très différent d'utiliser ERR_MALLOC, ou mieux encore MSGERR_MALLOC (ou MsgErr_malloc, si tu préfères un style plus discret et qui ne permet pas de croire qu'il s'agisse d'une valeur du pré-processeur).
Oui, effectivement, il faut prévoir une convention pour repérer les chaînes constants qui ne sont pas des macros.
-- Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
Antoine Leca scripsit:
Le 08/05/2009 11:56, mpg écrivit :
Comment choisir entre une définition de macro ou une définition de
variable avec le qualificateur const ?
En 2009, le conseil normal, c'est de préférer const (lorsque c'est
possible).
Ok.
Là où cela risque de poser le plus de difficultés, c'est pour les
constantes entières (genre le debug.h de ton exemple), et il y a de
grandes chances que tu sois obligé d'utiliser des valeurs du
pré-processeur (#define), surtout pour les dimensions de tableaux.
Ce qui est quand même très laid de mon point de vue, mais moi je suis
complètement imbibé d'un style qui n'est plus moderne...
1º err_malloc n'est PAS une constante... il est parfaitement possible
d'écrire dans un autre coin du programme :
err_malloc = "tout va bien, billg aux commandes";
err_realloc = "mauvaise utilisation de strtol";
même si je ne pense pas que ce soit l'effet escompté...
2º techniquement ce code a un comportement indéfini (et d'ailleurs, un
compilateur normal va probablement râler) : la déclaration dans
erreurs.h annonce que la chaîne est modifiable, et le compilateur peut
prendre avantage de cette information, par exemple en supposant que la
chaîne est allouée dans l'espace réservé aux chaînes modifiables ; mais
la définition de erreurs.c va dans l'autre sens, et spécifie que les
contenus des chaînes ne sont pas modifiables, donc le même compilateur
devrait les alloués ailleurs, peut-être en mémoire en lecture seule (ROM)...
Donc en remplaçant par
extern const char * const err_malloc;
ça devient correct ? Ceci dit, c'est vrai que c'est un peu plus lourd
syntaxiquement qu'un define, comme ça.
3º rien à l'utilisation ne permet de remarquer que err_malloc est une
chaîne constante ; c'est très différent d'utiliser ERR_MALLOC, ou mieux
encore MSGERR_MALLOC (ou MsgErr_malloc, si tu préfères un style plus
discret et qui ne permet pas de croire qu'il s'agisse d'une valeur du
pré-processeur).
Oui, effectivement, il faut prévoir une convention pour repérer les
chaînes constants qui ne sont pas des macros.
--
Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu
http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
Comment choisir entre une définition de macro ou une définition de variable avec le qualificateur const ?
En 2009, le conseil normal, c'est de préférer const (lorsque c'est possible).
Ok.
Là où cela risque de poser le plus de difficultés, c'est pour les constantes entières (genre le debug.h de ton exemple), et il y a de grandes chances que tu sois obligé d'utiliser des valeurs du pré-processeur (#define), surtout pour les dimensions de tableaux.
Ce qui est quand même très laid de mon point de vue, mais moi je suis complètement imbibé d'un style qui n'est plus moderne...
1º err_malloc n'est PAS une constante... il est parfaitement possible d'écrire dans un autre coin du programme : err_malloc = "tout va bien, billg aux commandes"; err_realloc = "mauvaise utilisation de strtol"; même si je ne pense pas que ce soit l'effet escompté...
2º techniquement ce code a un comportement indéfini (et d'ailleurs, un compilateur normal va probablement râler) : la déclaration dans erreurs.h annonce que la chaîne est modifiable, et le compilateur peut prendre avantage de cette information, par exemple en supposant que la chaîne est allouée dans l'espace réservé aux chaînes modifiables ; mais la définition de erreurs.c va dans l'autre sens, et spécifie que les contenus des chaînes ne sont pas modifiables, donc le même compilateur devrait les alloués ailleurs, peut-être en mémoire en lecture seule (ROM)...
Donc en remplaçant par
extern const char * const err_malloc;
ça devient correct ? Ceci dit, c'est vrai que c'est un peu plus lourd syntaxiquement qu'un define, comme ça.
3º rien à l'utilisation ne permet de remarquer que err_malloc est une chaîne constante ; c'est très différent d'utiliser ERR_MALLOC, ou mieux encore MSGERR_MALLOC (ou MsgErr_malloc, si tu préfères un style plus discret et qui ne permet pas de croire qu'il s'agisse d'une valeur du pré-processeur).
Oui, effectivement, il faut prévoir une convention pour repérer les chaînes constants qui ne sont pas des macros.
-- Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
-ed-
On 8 mai, 13:56, mpg <mpg+ wrote:
Bonjour,
Comment choisir entre une définition de macro ou une définition de variable avec le qualificateur const ?
Comme son nom l'indique, une "variable avec const" est une variable et pas une expression constante. C'est donc un objet en mémoire qui dispose d'une adresse et dont l'accès ne peut se fair qu'en lecture seule. Mais ça reste une 'l-value' (possibilité d'être le membre de gauche d'une expression d'affectation). Il est donc techniquement possible de modifier la valeur en utilisant un cast et l'opérateur d'affectation, mais le résultat est indéfini (il existe des solutions donnant un résultat défini).
Par contre, une expression constante n'est pas une l-value et ne peut donc pas être modifiée. (encore qu'une macro puisse être supprimée -- #undef -- et définie à nouveau...). Un enum est plus 'stable' (mais ne peut générer qu'un entier).
J'ai bien lu la réponse 5.4 de la FAQ, et je vois bien pourquoi « ça n'a rien à voir », sauf que je n'arrive pas à percevoir en quoi ça doit influencer le choix entre le s deux dans la pratique.
Par exemple, il me semble qu'on voit couramment des définitions comme
/* debug.h */ #define KPSE_DEBUG_STAT 0 /* stat calls */ #define KPSE_DEBUG_HASH 1 /* hash lookups */ #define KPSE_DEBUG_FOPEN 2 /* fopen/fclose cal ls */ /* etc */
Oui, ce sont clairement des expression constantes. On aurait pu faire :
Est-ce que ça dépend du type (entier, chaîne) de la constante ? Est -ce que ça fait une différence technique ou bien est-ce une question de style ?
Comme son nom ne l'indique pas, 'const' a le sens de 'readonly' . En effet il signifie clairement 'variable à lecture seule'. C'est le cas des chaines de caractères qui ne peuvent être modifiées. Il ne signifie pas 'expression constante'.
On 8 mai, 13:56, mpg <mpg+n...@elzevir.fr> wrote:
Bonjour,
Comment choisir entre une définition de macro ou une définition de
variable avec le qualificateur const ?
Comme son nom l'indique, une "variable avec const" est une variable et
pas une expression constante. C'est donc un objet en mémoire qui
dispose d'une adresse et dont l'accès ne peut se fair qu'en lecture
seule. Mais ça reste une 'l-value' (possibilité d'être le membre de
gauche d'une expression d'affectation). Il est donc techniquement
possible de modifier la valeur en utilisant un cast et l'opérateur
d'affectation, mais le résultat est indéfini (il existe des solutions
donnant un résultat défini).
Par contre, une expression constante n'est pas une l-value et ne peut
donc pas être modifiée. (encore qu'une macro puisse être supprimée --
#undef -- et définie à nouveau...). Un enum est plus 'stable' (mais ne
peut générer qu'un entier).
J'ai bien lu la réponse 5.4 de la
FAQ, et je vois bien pourquoi « ça n'a rien à voir », sauf que je
n'arrive pas à percevoir en quoi ça doit influencer le choix entre le s
deux dans la pratique.
Par exemple, il me semble qu'on voit couramment des définitions comme
/* debug.h */
#define KPSE_DEBUG_STAT 0 /* stat calls */
#define KPSE_DEBUG_HASH 1 /* hash lookups */
#define KPSE_DEBUG_FOPEN 2 /* fopen/fclose cal ls */
/* etc */
Oui, ce sont clairement des expression constantes. On aurait pu
faire :
Est-ce que ça dépend du type (entier, chaîne) de la constante ? Est -ce
que ça fait une différence technique ou bien est-ce une question de
style ?
Comme son nom ne l'indique pas, 'const' a le sens de 'readonly' . En
effet il signifie clairement 'variable à lecture seule'. C'est le cas
des chaines de caractères qui ne peuvent être modifiées. Il ne
signifie pas 'expression constante'.
Comment choisir entre une définition de macro ou une définition de variable avec le qualificateur const ?
Comme son nom l'indique, une "variable avec const" est une variable et pas une expression constante. C'est donc un objet en mémoire qui dispose d'une adresse et dont l'accès ne peut se fair qu'en lecture seule. Mais ça reste une 'l-value' (possibilité d'être le membre de gauche d'une expression d'affectation). Il est donc techniquement possible de modifier la valeur en utilisant un cast et l'opérateur d'affectation, mais le résultat est indéfini (il existe des solutions donnant un résultat défini).
Par contre, une expression constante n'est pas une l-value et ne peut donc pas être modifiée. (encore qu'une macro puisse être supprimée -- #undef -- et définie à nouveau...). Un enum est plus 'stable' (mais ne peut générer qu'un entier).
J'ai bien lu la réponse 5.4 de la FAQ, et je vois bien pourquoi « ça n'a rien à voir », sauf que je n'arrive pas à percevoir en quoi ça doit influencer le choix entre le s deux dans la pratique.
Par exemple, il me semble qu'on voit couramment des définitions comme
/* debug.h */ #define KPSE_DEBUG_STAT 0 /* stat calls */ #define KPSE_DEBUG_HASH 1 /* hash lookups */ #define KPSE_DEBUG_FOPEN 2 /* fopen/fclose cal ls */ /* etc */
Oui, ce sont clairement des expression constantes. On aurait pu faire :
Est-ce que ça dépend du type (entier, chaîne) de la constante ? Est -ce que ça fait une différence technique ou bien est-ce une question de style ?
Comme son nom ne l'indique pas, 'const' a le sens de 'readonly' . En effet il signifie clairement 'variable à lecture seule'. C'est le cas des chaines de caractères qui ne peuvent être modifiées. Il ne signifie pas 'expression constante'.