"static const" vs "# define vs " enum"

lequel est le mieux à utiliser parmi les énoncés ci-dessous en C?

static const int var = 5;

ou

#define var 5

ou

enum { var = 5 };
490
demandé sur Housy 2009-11-04 17:19:24

17 réponses

en général:

static const

parce qu'il respecte le champ d'application et est sans danger.

la seule mise en garde que je puisse voir: si vous voulez que la variable soit éventuellement définie sur la ligne de commande. Il y a encore une alternative:

#ifdef VAR // Very bad name, not long enough, too general, etc..
  static int const var = VAR;
#else
  static int const var = 5; // default value
#endif

dans la mesure du possible, au lieu des macros / ellipses, utilisez une alternative sans risque.

si vous avez vraiment besoin d'aller avec une macro (par exemple, vous voulez __FILE__ ou __LINE__ ), alors vous feriez mieux de nommer votre macro très soigneusement: dans sa convention de nommage Boost recommande tous les majuscules, en commençant par le nom du projet (ici BOOST_), tout en parcourant la bibliothèque, vous remarquerez que c'est (généralement) suivi du nom de la zone particulière (bibliothèque) puis avec un nom significatif.

il rend généralement pour les noms longs :)

258
répondu Matthieu M. 2012-09-02 09:09:48

cela dépend de ce pour quoi vous avez besoin de la valeur. Vous (et tous les autres jusqu'à présent) avez omis la troisième alternative:

  1. static const int var = 5;
  2. #define var 5
  3. enum { var = 5 };

en Ignorant les questions sur le choix du nom, puis:

  • Si vous avez besoin de passer un pointeur autour de vous, vous devez utiliser (1).
  • puisque (2) est apparemment un option, vous n'avez pas besoin de passer des pointeurs autour.
  • les deux (1) et (3) ont un symbole dans la table de symboles du débogueur - qui rend le débogage plus facile. Il est plus probable que (2) n'aura pas de symbole, vous laissant vous demander ce que c'est.
  • (1) ne peut pas être utilisé comme une dimension pour les tableaux à portée globale; les deux (2) et (3) peuvent.
  • (1) ne peut pas être utilisé comme dimension pour les tableaux statiques à la portée de la fonction; les deux (2) et (3) peuvent.
  • sous C99, tous ceux-ci peuvent être utilisés pour les réseaux locaux. Techniquement, l'utilisation de (1) impliquerait l'utilisation d'un VLA (variable-length array), bien que la dimension référencée par 'var' soit bien sûr fixe à la taille 5.
  • (1) ne peut pas être utilisé dans des endroits comme les instructions switch; deux (2) et (3) peut.
  • (1) ne peut pas être utilisé pour initialiser les variables statiques; les deux (2) et (3) peuvent.
  • (2) peut changer le code que vous ne vouliez pas changer parce qu'il est utilisé par le préprocesseur; les deux (1) et (3) n'auront pas d'effets secondaires inattendus comme celui-ci.
  • vous pouvez détecter si (2) a été réglé dans le préprocesseur; ni (1) Ni (3) ne le permet.

ainsi, dans la plupart des contextes, préfèrent le "enum" plutôt que les alternatives. Autrement, le premier et le dernier point sont susceptibles d'être les facteurs de contrôle - et vous devez réfléchir davantage si vous avez besoin de satisfaire les deux à la fois.

si vous demandiez à propos de C++, alors vous utiliseriez l'option (1) - la const statique - à chaque fois.

589
répondu Jonathan Leffler 2015-12-04 18:22:11

en C, en particulier? Dans C la bonne réponse est: utiliser #define (ou, le cas échéant, enum )

alors qu'il est bénéfique d'avoir les propriétés de cadrage et de typage d'un const objet, en réalité const objets en C (par opposition à C++) ne sont pas de vraies constantes et sont donc généralement inutiles dans la plupart des cas pratiques.

ainsi, dans C le choix devrait être déterminé par la façon dont vous prévoyez d'utiliser votre constante. Exemple, vous ne pouvez pas utiliser un objet const int comme étiquette case (alors qu'une macro fonctionnera). Vous ne pouvez pas utiliser un objet const int comme une largeur de champ bit (alors qu'une macro fonctionnera). En C89 / 90, vous ne pouvez pas utiliser un objet const pour spécifier une taille de tableau (alors qu'une macro fonctionnera). Même en C99, vous ne pouvez pas utiliser un objet const pour spécifier une taille de tableau lorsque vous avez besoin d'un tableau non- VLA .

si cela est important pour vous, alors il déterminera votre choix. La plupart du temps, vous n'aurez pas d'autre choix que d'utiliser #define en C. et n'oubliez pas une autre alternative, qui produit de vraies constantes en C - enum .

en C++ const les objets sont de vraies constantes, donc en C++ il est presque toujours préférable de préférer la variante const (pas besoin d'expliciter static en C++ cependant).

94
répondu AnT 2012-09-02 09:16:39

la différence entre static const et #define est que le premier utilise la mémoire et le dernier n'utilise pas la mémoire pour le stockage. Deuxièmement, vous ne pouvez pas passer l'adresse d'un #define alors que vous, vous pouvez passer l'adresse d'un static const . En fait, cela dépend des circonstances dans lesquelles nous sommes, nous devons en choisir un parmi ces deux. Les deux sont à leur meilleur dans des circonstances différentes. Ne présumez pas que l'un est meilleur que l'autre... :- )

Si cela aurait été le cas, Dennis Ritchie aurait gardé le meilleur d'un seul... hahaha... :- )

28
répondu wrapperm 2012-09-02 09:30:06

en C #define est beaucoup plus populaire. Vous pouvez utiliser ces valeurs pour déclarer des tailles de tableau par exemple:

#define MAXLEN 5

void foo(void) {
   int bar[MAXLEN];
}

ANSI C ne vous permet pas d'utiliser static const s dans ce contexte autant que je sache. Dans C++, vous devriez éviter les macros dans ces cas. Vous pouvez écrire

const int maxlen = 5;

void foo() {
   int bar[maxlen];
}

et même omettre static parce que le lien interne est implicite par const déjà [en C++ seulement].

14
répondu sellibitze 2011-01-21 21:06:11

un autre inconvénient de const dans C est que vous ne pouvez pas utiliser la valeur en initialisant un autre const .

static int const NUMBER_OF_FINGERS_PER_HAND = 5;
static int const NUMBER_OF_HANDS = 2;

// initializer element is not constant, this does not work.
static int const NUMBER_OF_FINGERS = NUMBER_OF_FINGERS_PER_HAND 
                                     * NUMBER_OF_HANDS;

Même cela ne fonctionne pas avec un const puisque le compilateur ne le voit pas comme une constante:

static uint8_t const ARRAY_SIZE = 16;
static int8_t const lookup_table[ARRAY_SIZE] = {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // ARRAY_SIZE not a constant!

je serais heureux d'utiliser const dactylographié dans ces cas, sinon...

13
répondu Gauthier 2011-01-24 13:32:02

Si vous pouvez sortir avec elle, static const a beaucoup d'avantages. Il obéit aux principes de la portée normale, est visible dans un débogueur, et obéit généralement aux règles auxquelles obéissent les variables.

cependant, au moins dans la norme C d'origine, ce n'est pas vraiment une constante. Si vous utilisez #define var 5 , vous pouvez écrire int foo[var]; comme une déclaration, mais vous ne pouvez pas le faire (sauf comme une extension de compilateur" avec static const int var = 5; . Ce n'est pas le cas en C++, où La version static const peut être utilisée partout où la version #define le peut, et je crois que c'est aussi le cas avec la C99.

cependant, ne nommez jamais une constante #define avec un nom en minuscules. Il remplace toute utilisation possible de ce nom jusqu'à la fin de l'unité de traduction. Les Macro constantes devraient être dans ce qui est effectivement leur propre espace de nom, qui est traditionnellement toutes les lettres majuscules, peut-être avec un préfixe.

9
répondu David Thornley 2009-11-04 14:38:24

j'ai écrit quick test program pour démontrer une différence:

#include <stdio.h>

enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};

#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32

int main(int argc, char *argv[]) {

   printf("%d, %d\n", DEFINED_DEFINED, ENUM_DEFINED);

   return(0);
}

ce compile avec ces erreurs et avertissements:

main.c:6:7: error: redefinition of enumerator 'ENUM_DEFINED'
enum {ENUM_DEFINED=32};
      ^
main.c:5:7: note: previous definition is here
enum {ENUM_DEFINED=16};
      ^
main.c:9:9: warning: 'DEFINED_DEFINED' macro redefined [-Wmacro-redefined]
#define DEFINED_DEFINED 32
        ^
main.c:8:9: note: previous definition is here
#define DEFINED_DEFINED 16
        ^

notez qu'enum donne une erreur quand define donne un avertissement.

6
répondu Michael Potter 2016-04-29 17:37:40

#define var 5 vous causera des problèmes si vous avez des choses comme mystruct.var .

par exemple,

struct mystruct {
    int var;
};

#define var 5

int main() {
    struct mystruct foo;
    foo.var = 1;
    return 0;
}

le préprocesseur le remplacera et le code ne sera pas compilé. Pour cette raison, le style de codage traditionnel suggère toutes les constantes #define s utilise des lettres majuscules pour éviter les conflits.

5
répondu Non-maskable Interrupt 2012-09-02 09:33:26

il est toujours préférable d'utiliser const, au lieu de #define. C'est parce que const est traité par le compilateur et #define du préprocesseur. C'est comme si #define lui-même ne faisait pas partie du code (en gros).

exemple:

#define PI 3.1416

le nom symbolique PI peut ne jamais être vu par les compilateurs; il peut être supprimé par le préprocesseur avant même que le code source ne parvienne à un compilateur. En conséquence, le nom PI peut ne pas être entré dans le la table des symboles. Cela peut prêter à confusion si vous obtenez une erreur lors de la compilation impliquant l'utilisation de la constante, parce que le message d'erreur peut se référer à 3.1416, pas à PI. SI PI était défini dans un fichier d'en-tête que vous n'avez pas écrit, vous n'auriez aucune idée d'où vient ce 3.1416.

ce problème peut également apparaître dans un débogueur symbolique, parce que, encore une fois, le nom avec lequel vous programmez peut ne pas être dans la table de symboles.

Solution:

const double PI = 3.1416; //or static const...
5
répondu suren 2016-01-01 17:48:29

la définition

const int const_value = 5;

ne définit pas toujours une valeur constante. Certains compilateurs (par exemple tcc 0.9.26 ) n'attribuent que la mémoire identifiée par le nom"Constance". En utilisant l'identifiant "Constance" vous ne pouvez pas modifier cette mémoire. Mais vous pouvez encore modifier la mémoire en utilisant un autre identifiant:

const int const_value = 5;
int *mutable_value = (int*) &const_value;
*mutable_value = 3;
printf("%i", const_value); // The output may be 5 or 3, depending on the compiler.

s'entend de la définition de

#define CONST_VALUE 5

est le seul moyen de définissez une valeur constante qui ne peut être modifiée par aucun moyen.

4
répondu user2229691 2016-01-01 17:44:02

ne pensez pas qu'il y ait une réponse pour "ce qui est toujours mieux" mais, comme Matthieu a dit

static const

est un type sûr. Mon plus grand pet peeve avec #define , cependant, est lors du débogage dans Visual Studio vous ne pouvez pas regarder la variable. Il donne une erreur que le symbole ne peut pas être trouvé.

3
répondu Afcrowe 2012-09-02 09:11:19

soit dit en passant, une alternative à #define , qui fournit une portée appropriée mais se comporte comme une constante" réelle", est"enum". Par exemple:

enum {number_ten = 10;}

dans de nombreux cas, il est utile de définir les types énumérés et de créer des variables de ces types; si cela est fait, les débogueurs peuvent être en mesure d'Afficher des variables selon leur nom d'énumération.

une mise en garde importante à faire, cependant: en C++, les types énumérés ont limité compatibilité avec les entiers. Par exemple, par défaut, on ne peut plus effectuer de l'arithmétique. Je trouve que c'est un comportement par défaut curieux pour enums; alors qu'il aurait été agréable d'avoir un type "strict enum", étant donné le désir d'avoir C++ généralement compatible avec C, je pense que le comportement par défaut d'un type "enum" devrait être interchangeable avec des entiers.

3
répondu supercat 2012-09-02 09:32:14

bien que la question portait sur les entiers, il est intéressant de noter que #define et enums sont inutiles si vous avez besoin d'une structure ou chaîne constante. Ceux-ci sont généralement passés à des fonctions de pointeurs. (Avec des cordes, c'est nécessaire; avec des structures, c'est beaucoup plus efficace.)

en ce qui concerne les entiers, si vous êtes dans un environnement embarqué avec une mémoire très limitée, vous pourriez avoir besoin de vous soucier de l'endroit où la constante est stockée et comment les accès à elle sont compilés. Compilateur pourrait ajouter deux consts au moment de l'exécution, mais ajouter deux #définit au moment de la compilation. Une constante # define peut être convertie en une ou plusieurs instructions MOV [immédiates], ce qui signifie que la constante est effectivement stockée dans la mémoire du programme. Const constante sera stocké dans le .const section dans la mémoire de données. Dans les systèmes avec une architecture de Harvard, il pourrait y avoir des différences dans la performance et l'utilisation de la mémoire, bien qu'elles soient probablement petites. Ils pourraient être importants pour l'optimisation du noyau dur des boucles internes.

2
répondu Adam Haun 2018-01-05 21:17:24

une simple différence:

au moment du prétraitement, la constante est remplacée par sa valeur. Donc, vous ne pouviez pas appliquer l'opérateur de déréférencement à définir, mais vous pouvez appliquer l'opérateur de déréférencement à une variable.

comme vous le supposeriez, define est plus rapide que const statique.

, par exemple, ayant:

#define mymax 100

vous ne pouvez pas faire printf("address of constant is %p",&mymax); .

mais ayant

const int mymax_var=100

vous pouvez faire printf("address of constant is %p",&mymax_var); .

pour être plus clair, le define est remplacé par sa valeur au stade du Pré-traitement, de sorte que nous n'avons Aucune variable stockée dans le programme. Nous avons juste le code du segment de texte du programme où le define a été utilisé.

Cependant, pour const statique nous avons une variable qui est affectée quelque part. Pour gcc, const statique sont alloués dans le segment de texte du programme.

ci-dessus, je voulais parler de l'opérateur de référence donc remplacer dereference avec référence.

1
répondu mihaitzateo 2016-01-01 17:47:12

nous avons regardé le code assembleur produit sur le MBF16X... Les deux variantes donnent le même code pour les opérations arithmétiques (ajouter immédiat, par exemple).

donc const int est préféré pour le contrôle de type tandis que #define est de style ancien. Peut-être que c'est spécifique au compilateur. Vérifiez donc votre code assembleur produit.

0
répondu guest 2016-01-01 17:49:24

Je ne suis pas sûr que j'ai raison mais à mon avis appeler #define valeur d est beaucoup plus rapide que d'appeler n'importe quelle autre variable normalement déclarée (ou valeur const). C'est parce que quand le programme est en cours d'exécution et qu'il a besoin d'utiliser une variable normalement déclarée, il a besoin de sauter à l'endroit exact dans la mémoire pour obtenir cette variable.

Au contraire de #define d valeur, le programme n'a pas besoin d'aller à toute la mémoire allouée, il faut juste de la valeur. Si #define myValue 7 et le programme appelé myValue , il se comporte exactement comme quand il appelle 7 .

0
répondu pajczur 2018-10-05 19:59:49