«Const statique» vs «#define» vs «enum»

585

Lequel est préférable d'utiliser parmi les déclarations ci-dessous en C?

static const int var = 5;

ou

#define var 5

ou

enum { var = 5 };
Vijay
la source
35
Fait intéressant, c'est presque exactement la même question que stackoverflow.com/questions/1637332/static-const-vs-define . La seule différence est que cette question concerne le C ++, et celle-ci concerne le C. Puisque ma réponse était spécifique au C ++, je dis que cela ne les rend pas identiques, mais d'autres peuvent être en désaccord.
TED
53
Pas identique, certainement. Il y a beaucoup de domaines où C ++ autorise la syntaxe C pour des raisons de compatibilité. Dans ces cas, des questions comme «quelle est la meilleure façon de faire X» auront des réponses différentes en C ++. Par exemple, initialisation d'objet.
MSalters
Comment cela n'est-il pas basé sur une opinion? Ils ont chacun un but différent
Sam Hammamy
1
@RobertSsupportsMonicaCellio, oui. Merci pour l'intimation
Vijay

Réponses:

690

Cela dépend de la valeur dont vous avez besoin. Vous (et tout le monde jusqu'à présent) avez omis la troisième alternative:

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

Ignorer les problèmes liés au choix du nom, puis:

  • Si vous devez passer un pointeur, vous devez utiliser (1).
  • Puisque (2) est apparemment une option, vous n'avez pas besoin de passer des pointeurs.
  • (1) et (3) ont un symbole dans la table des symboles du débogueur - ce qui facilite le débogage. 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 dimension pour des tableaux à portée mondiale; (2) et (3) le peuvent.
  • (1) ne peut pas être utilisé comme dimension pour les tableaux statiques au niveau de la fonction; (2) et (3) le peuvent.
  • Sous C99, tous ces éléments peuvent être utilisés pour les tableaux locaux. Techniquement, l'utilisation de (1) impliquerait l'utilisation d'un VLA (tableau de longueur variable), bien que la dimension référencée par 'var' soit bien sûr fixée à la taille 5.
  • (1) ne peut pas être utilisé dans des endroits comme les instructions switch; (2) et (3) le peuvent.
  • (1) ne peut pas être utilisé pour initialiser des variables statiques; (2) et (3) le peuvent.
  • (2) peut changer le code que vous ne vouliez pas changer car il est utilisé par le préprocesseur; (1) et (3) n'auront pas d'effets secondaires inattendus comme ça.
  • Vous pouvez détecter si (2) a été défini dans le préprocesseur; ni (1) ni (3) ne le permettent.

Donc, dans la plupart des contextes, préférez l'énumération aux alternatives. Sinon, le premier et le dernier point sont probablement les facteurs déterminants - et vous devez réfléchir davantage si vous devez satisfaire les deux à la fois.

Si vous posiez des questions sur C ++, alors vous utiliseriez l'option (1) - la constante statique - à chaque fois.

Jonathan Leffler
la source
111
liste fantastique! Un inconvénient enumest qu'ils sont implémentés en tant que int([C99] 6.7.2.2/3). A #definevous permet de spécifier non signé et long avec Uet Lsuffixes, et constvous permet de donner un type. enumpeut provoquer des problèmes avec les conversions de type habituelles.
Gauthier
37
(2) les gens se plaignent TOUJOURS de la sécurité du type. Je ne comprends jamais pourquoi ne pas simplement utiliser "#define var ((int) 5)" et hourra, vous avez obtenu la sécurité de type avec un define.
Ingo Blackman
6
@RedX: il faudrait être dans un environnement très particulier pour l'espace à une préoccupation. Cela dit, enumni #definen'utilise d'espace supplémentaire en soi. La valeur apparaîtra dans le code objet dans le cadre des instructions plutôt que d'être allouée au stockage dans le segment de données ou dans le segment de mémoire ou sur la pile. Vous aurez de l'espace alloué pour le static const int, mais le compilateur pourrait l'optimiser si vous ne prenez pas d'adresse.
Jonathan Leffler
15
Un autre «vote» pour enums (et static const): ils ne peuvent pas être modifiés. a definepeut être #undefine'd où an enumet static constsont fixés à la valeur donnée.
Daan Timmer
15
@QED: Non, merci. Une simple constante est sécurisée entre parenthèses. Ou, montrez-moi comment un programme que l'on peut légitimement s'attendre à compiler serait modifié en n'ayant pas les 5 entre parenthèses. Si c'était l'argument d'une macro de style fonction, ou s'il y avait des opérateurs dans l'expression, alors vous auriez raison de me blâmer si je n'avais pas inclus les parenthèses. Mais ce n'est pas le cas ici.
Jonathan Leffler
282

En général:

static const

Parce qu'il respecte la portée et est de type sécurisé.

La seule mise en garde que j'ai pu 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 de macros / points de suspension, utilisez une alternative de type sécurisé.

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 attentivement: dans sa convention de dénomination, Boost recommande tout en majuscules, en commençant par le nom du projet (ici BOOST_ ), en parcourant la bibliothèque, vous remarquerez qu'il est (généralement) suivi du nom de la zone particulière (bibliothèque) puis d'un nom significatif.

Cela donne généralement de longs noms :)

Matthieu M.
la source
2
D'accord - également avec #define, il y a un danger général de déformation du code car le préprocesseur n'a pas connaissance de la syntaxe.
NeilDurant
10
Il vaut mieux utiliser #if que #ifdef, mais sinon je suis d'accord. +1.
Tim Post
58
C'est l'évangélisation C ++ standard. La réponse ci-dessous est BEAUCOUP plus claire pour expliquer quelles sont réellement les options et ce qu'elles signifient. En particulier: je viens d'avoir un problème avec "static const". Quelqu'un l'a utilisé pour définir environ 2000 "constantes" dans un fichier d'en-tête. Ensuite, ce fichier d'en-tête a été inclus dans environ 100 fichiers ".c" et ".cpp". => 8 Mo pour "consts". Génial. Oui, je sais que vous pouvez utiliser un éditeur de liens pour supprimer les consts non référencés, mais cela vous laisse toujours les "consts" qui SONT référencés. Manque d'espace ce qui ne va pas avec cette réponse.
Ingo Blackman
2
@IngoBlackman: Avec un bon compilateur, seuls ceux staticdont l'adresse est prise doivent rester; et si l'adresse est prise, on n'aurait pas pu utiliser un #defineou enum(pas d'adresse) ... donc je ne vois vraiment pas quelle alternative aurait pu être utilisée. Si vous pouvez vous débarrasser de "l'évaluation du temps de compilation", vous cherchez peut-être à la extern constplace.
Matthieu M.
15
@Tim Post: #ifpeut-être préférable #ifdefaux booléens, mais dans ce cas, il serait impossible de définir varà 0partir de la ligne de commande. Donc, dans ce cas, #ifdefcela a plus de sens, tant qu'il 0y a une valeur légale pour var.
Maarten
108

En C, plus précisément? En C, la bonne réponse est: utiliser #define(ou, le cas échéant, enum)

Bien qu'il soit avantageux d'avoir les propriétés de portée et de typage d'un constobjet, en réalité, les constobjets 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, en C, le choix doit être déterminé par la façon dont vous prévoyez d'utiliser votre constante. Par exemple, vous ne pouvez pas utiliser un const intobjet comme caseétiquette (alors qu'une macro fonctionnera). Vous ne pouvez pas utiliser un const intobjet comme largeur de champ binaire (alors qu'une macro fonctionnera). En C89 / 90, vous ne pouvez pas utiliser un constobjet pour spécifier une taille de tableau (alors qu'une macro fonctionnera). Même en C99, vous ne pouvez pas utiliser un constobjet pour spécifier une taille de tableau lorsque vous avez besoin d'un tableau non VLA .

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

En C ++, les constobjets sont de vraies constantes, donc en C ++ il est presque toujours préférable de préférer la constvariante (pas besoin d'explicite staticen C ++ cependant).

Fourmi
la source
6
"vous ne pouvez pas utiliser un objet const int comme étiquette de casse (alors qu'une macro fonctionnera)" ---> En ce qui concerne cette déclaration, j'ai testé une variable const int en C dans le commutateur, elle fonctionne ....
john
8
@john: Eh bien, vous devez fournir le code que vous avez testé et nommer le compilateur spécifique. L'utilisation d' const intobjets dans les étiquettes de cas est illégale dans toutes les versions du langage C. (Bien sûr, votre compilateur est libre de le prendre en charge comme une extension de langage non standard de type C ++.)
AnT
11
"... et sont donc généralement inutiles dans la plupart des cas pratiques ." Je ne suis pas d'accord. Ils sont parfaitement utiles tant que vous n'avez pas besoin d'utiliser le nom comme expression constante. Le mot "constant" en C signifie quelque chose qui peut être évalué au moment de la compilation; constsignifie en lecture seule. const int r = rand();est parfaitement légal.
Keith Thompson
En c ++, il est préférable d'utiliser constexprpar rapport à constspécialement avec les stlconteneurs comme arrayou bitset.
Mayukh Sarkar
1
@john, vous devez avoir testé dans la switch()déclaration, pas dans caseun. Je viens juste de m'attraper sur celui-ci aussi
Hi
32

La différence entre static constet #defineest 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 transmettre l'adresse d'un #definealors que vous pouvez transmettre l'adresse d'un static const. En fait, cela dépend de la situation dans laquelle nous nous trouvons, nous devons en sélectionner un parmi ces deux. Les deux sont à leur meilleur dans des circonstances différentes. Veuillez ne pas supposer que l'un est meilleur que l'autre ... :-)

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

emballage
la source
6
+1 pour mentionner la mémoire, certains systèmes embarqués n'en ont pas encore beaucoup, même si je commencerais probablement par utiliser des constantes statiques et ne changerais en #defines que si nécessaire.
fluffyben
3
Je viens de le tester. En effet, const int utilise de la mémoire supplémentaire par rapport à #define ou enum. Puisque nous programmons des systèmes embarqués, nous ne pouvons pas nous permettre d'utiliser la mémoire supplémentaire. Nous allons donc recommencer à utiliser #define ou enum.
Davide Andrea
2
En pratique, il n'est pas vrai (plus) que la constmémoire utilise. GCC (testé avec 4.5.3 et quelques versions plus récentes) optimise facilement le const inten un littéral direct dans votre code lors de l'utilisation de -O3. Donc, si vous faites du développement intégré à faible RAM (par exemple AVR), vous pouvez utiliser en toute sécurité les constantes C si vous utilisez GCC ou un autre compilateur compatible. Je ne l'ai pas testé mais je m'attends à ce que Clang fasse la même chose.
Raphael
19

En C #defineest 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 consts dans ce contexte pour autant que je sache. En C ++, vous devez éviter les macros dans ces cas. Tu peux écrire

const int maxlen = 5;

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

et même laisser de côté staticparce que la liaison interne est impliquée par constdéjà [en C ++ uniquement].

sellibitze
la source
1
Que voulez-vous dire par «lien interne»? Je peux avoir const int MY_CONSTANT = 5;dans un fichier et y accéder avec extern const int MY_CONSTANT;dans un autre. Je n'ai pu trouver aucune information dans la norme (C99 au moins) sur la constmodification du comportement par défaut "6.2.2: 5 Si la déclaration d'un identificateur pour un objet a une portée de fichier et aucun spécificateur de classe de stockage, sa liaison est externe".
Gauthier
@Gauthier: Désolé, à ce sujet. J'aurais dû dire "est impliqué par const déjà dans le langage C ++". Ceci est spécifique à C ++.
sellibitze
@sellibitze c'est sympa de voir quelques arguments en cours de route au lieu de tonnes d' OPINION S'il y avait un bonus pour de vrais arguments, vous l'avez!
Paul
1
Depuis C99, votre deuxième extrait est légal. barest un VLA (tableau de longueur variable); le compilateur est susceptible de générer du code comme si sa longueur était constante.
Keith Thompson
14

Un autre inconvénient de constC est que vous ne pouvez pas utiliser la valeur pour en initialiser 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 car 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 tapé constdans ces cas, sinon ...

Gauthier
la source
5
Un peu tard dans le match, mais cette question est venue dans une autre question. Chercher à comprendre pourquoi votre static uint8_t const ARRAY_SIZE = 16;compilation soudaine ne peut plus être un peu difficile, en particulier lorsque le #define ARRAY_SIZE 256est enfoui à dix couches profondément dans un réseau d'en-têtes emmêlé. Ce nom tout en majuscules ARRAY_SIZEdemande des ennuis. Réservez ALL_CAPS pour les macros et ne définissez jamais une macro qui n'est pas sous la forme ALL_CAPS.
David Hammen
@David: de bons conseils que je suivrai.
Gauthier
1
4 ans plus tard, vous m'avez fait gagner beaucoup de temps à comprendre pourquoi je ne pouvais pas "imbriquer" const. Cela pourrait être plus voté!
Plouff
11

Si vous pouvez vous en tirer, cela static constprésente de nombreux avantages. Il obéit aux principes de portée normaux, est visible dans un débogueur et obéit généralement aux règles auxquelles les variables obéissent.

Cependant, au moins dans la norme C d'origine, ce n'est pas réellement 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 en tant qu'extension de compilateur "avec static const int var = 5;. Ce n'est pas le cas en C ++, où la static constversion peut être utilisée partout où la #defineversion le peut, et je crois que cela c'est aussi le cas avec C99.

Cependant, ne nommez jamais une #defineconstante avec un nom en minuscule. Il remplacera toute utilisation possible de ce nom jusqu'à la fin de l'unité de traduction. Les macros constantes doivent être dans ce qui est effectivement leur propre espace de noms, qui est traditionnellement composé de majuscules, peut-être avec un préfixe.

David Thornley
la source
6
Malheureusement, ce n'est pas le cas avec C99. consten C99 n'est pas encore une vraie constante. Vous pouvez déclarer la taille du tableau avec un constdans C99, mais uniquement parce que C99 prend en charge les tableaux à longueur variable. Pour cette raison, cela ne fonctionnera que là où les VLA sont autorisés. Par exemple, même en C99, vous ne pouvez toujours pas utiliser a constpour déclarer la taille d'un tableau de membres dans a struct.
AnT
Bien qu'il soit correct que C99 ne vous laisse pas faire cela, GCC (testé avec 4.5.3) vous permettra parfaitement d'initialiser des tableaux avec une const inttaille comme s'il s'agissait d'une const C ++ ou d'une macro. Que vous souhaitiez dépendre de cet écart de GCC par rapport à la norme est bien sûr votre choix, j'irais personnellement avec lui à moins que vous ne puissiez vraiment prévoir d'utiliser un autre compilateur que GCC ou Clang, ce dernier a la même fonctionnalité ici (testé avec Clang 3.7).
Raphael
7

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 par le 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. Par conséquent, le nom PI peut ne pas être entré dans la table des symboles. Cela peut être déroutant si vous obtenez une erreur lors de la compilation impliquant l'utilisation de la constante, car le message d'erreur peut faire référence à 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, car, encore une fois, le nom avec lequel vous programmez peut ne pas figurer dans la table des symboles.

Solution:

const double PI = 3.1416; //or static const...
suren
la source
6

#define var 5vous 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 se compilera pas. Pour cette raison, le style de codage traditionnel suggère que toutes les constantes #defineutilisent des majuscules pour éviter les conflits.

Interruption non masquable
la source
6

J'ai écrit un programme de test rapide 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);
}

Cela se 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 que enum donne une erreur lorsque define donne un avertissement.

Michael Potter
la source
4

La définition

const int const_value = 5;

ne définit pas toujours une valeur constante. Certains compilateurs (par exemple tcc 0.9.26 ) allouent simplement de la mémoire identifiée avec le nom "const_value". En utilisant l'identifiant "const_value" vous ne pouvez pas modifier cette mémoire. Mais vous pouvez toujours 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.

Cela signifie que la définition

#define CONST_VALUE 5

est le seul moyen de définir une valeur constante qui ne peut en aucun cas être modifiée.

user2229691
la source
8
La modification d'une valeur constante à l'aide d'un pointeur est un comportement non défini. Si vous êtes prêt à vous y rendre, #definepeut également être modifié, en modifiant le code machine.
ugoren
Vous avez en partie raison. J'ai testé le code avec Visual Studio 2012 et il s'imprime 5. Mais on ne peut pas modifier #definecar c'est une macro de préprocesseur. Il n'existe pas dans le programme binaire. Si l'on voulait modifier tous les endroits où il CONST_VALUEétait utilisé, il fallait le faire un par un.
user2229691
3
@ugoren: Supposons que vous écriviez #define CONST 5, alors if (CONST == 5) { do_this(); } else { do_that(); }, et que le compilateur élimine la elsebranche. Comment proposez-vous de modifier le code machine pour passer CONSTà 6?
Keith Thompson
@KeithThompson, je n'ai jamais dit que cela pouvait se faire facilement et de manière fiable. Mais ce #definen'est pas à l'épreuve des balles.
ugoren
3
@ugoren: Mon argument est que "modifier le code machine" n'est pas un moyen sensé de reproduire l'effet de la modification de la valeur de a #define. La seule vraie façon de le faire est d'éditer le code source et de recompiler.
Keith Thompson
4

Bien que la question porte sur les entiers, il convient de noter que #define et les énumérations sont inutiles si vous avez besoin d'une structure ou d'une chaîne constante. Ceux-ci sont généralement transmis aux fonctions en tant que pointeurs. (Avec les chaînes, c'est obligatoire; avec les structures, c'est beaucoup plus efficace.)

En ce qui concerne les entiers, si vous êtes dans un environnement intégré avec une mémoire très limitée, vous devrez peut-être vous soucier de l'emplacement de stockage de la constante et de la façon dont les accès sont compilés. Le compilateur peut ajouter deux consts au moment de l'exécution, mais ajouter deux #defines 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. Une constante const sera stockée dans la section .const de la mémoire de données. Dans les systèmes avec une architecture Harvard, il pourrait y avoir des différences de performances et d'utilisation de la mémoire, bien qu'elles soient probablement petites. Ils peuvent être importants pour l'optimisation du noyau dur des boucles internes.

Adam Haun
la source
3

Ne pensez pas qu'il y ait une réponse pour "ce qui est toujours le meilleur" mais, comme l'a dit Matthieu

static const

est sûr de type. Ma plus grande bête noire #define, cependant, est que lors du débogage dans Visual Studio, vous ne pouvez pas regarder la variable. Cela donne une erreur indiquant que le symbole est introuvable.

Afcrowe
la source
1
"vous ne pouvez pas regarder la variable" Bon, ce n'est pas une variable. Cela ne change pas, pourquoi avez-vous besoin de le regarder? Vous pouvez trouver partout où il est utilisé simplement en recherchant l'étiquette. Pourquoi auriez-vous besoin (ou même envie) de regarder un #define?
Marshall Eubanks
3

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 des types énumérés et de créer des variables de ces types; si cela est fait, les débogueurs peuvent afficher les variables en fonction de leur nom d'énumération.

Cependant, une mise en garde importante: en C ++, les types énumérés ont une compatibilité limitée avec les entiers. Par exemple, par défaut, on ne peut pas effectuer d'arithmétique sur eux. Je trouve que c'est un comportement par défaut curieux pour les énumérations; alors qu'il aurait été bien d'avoir un type "enum strict", é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.

supercat
la source
1
En C, les constantes d'énumération sont toujours de type int, donc le "hack d'énumération" ne peut pas être utilisé avec d'autres types entiers. (Le type d' énumération est compatible avec certains types entiers définis par l'implémentation, pas nécessairement int, mais dans ce cas, le type est anonyme, donc cela n'a pas d'importance.)
Keith Thompson
@KeithThompson: Depuis que j'ai écrit ce qui précède, j'ai lu que MISRA-C squawk si un compilateur attribue un type autre qu'à intune variable de type énumération (que les compilateurs sont autorisés à faire) et on essaie d'assigner à une telle variable un membre de sa propre énumération. Je souhaite que les comités de normalisation ajoutent des moyens portables de déclarer des types entiers avec une sémantique spécifiée. N'IMPORTE QUELLE plate-forme, quelle que soit charsa taille, devrait être en mesure par exemple de déclarer un type qui encapsulera le mod 65536, même si le compilateur doit ajouter de nombreuses AND R0,#0xFFFFinstructions équivalentes.
supercat
Vous pouvez utiliser uint16_t, bien que ce ne soit bien sûr pas un type d'énumération. Il serait bien de laisser l'utilisateur spécifier le type entier utilisé pour représenter un type d'énumération donné, mais vous pouvez obtenir à peu près le même effet avec un typedefpour uint16_tet une série de #defines pour les valeurs individuelles.
Keith Thompson
1
@KeithThompson: Je comprends que pour des raisons historiques, nous sommes coincés avec le fait que certaines plates-formes seront considérées 2U < -1Lcomme vraies et d'autres comme fausses, et nous sommes maintenant coincés avec le fait que certaines plates-formes implémenteront une comparaison entre uint32_tet int32_tcomme signé et certains comme non signés, mais cela ne signifie pas que le Comité n'a pas pu définir un successeur de C vers le haut compatible qui inclut des types dont la sémantique serait cohérente sur tous les compilateurs.
supercat
1

Une simple différence:

Au moment du prétraitement, la constante est remplacée par sa valeur. Vous ne pouvez donc pas appliquer l'opérateur de déréférence à un define, mais vous pouvez appliquer l'opérateur de déréférence à une variable.

Comme vous le supposez, define est plus rapide que const statique.

Par exemple, avoir:

#define mymax 100

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

Mais ayant

const int mymax_var=100

tu peux 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, donc nous n'avons aucune variable stockée dans le programme. Nous avons juste le code du segment de texte du programme où la définition a été utilisée.

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

Ci-dessus, je voulais parler de l'opérateur de référence, alors remplacez la déréférence par la référence.

mihaitzateo
la source
1
Votre réponse est très fausse. Il s'agit de C, votre réponse concerne C ++, qui a une sémantique très différente pour le constqualificatif. C n'a pas de constantes symboliques autres que les constantes enum . A const intest une variable. Vous confondez également le langage et les implémentations spécifiques. Il n'y a aucune exigence où placer l'objet. Et ce n'est même pas vrai pour gcc: il place généralement constdes variables qualifiées dans la .rodatasection. Mais cela dépend de la plate-forme cible. Et vous voulez dire l'adresse de l'opérateur &.
trop honnête pour ce site
0

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

Il const intest donc préférable pour la vérification de type alors qu'il #defineest à l'ancienne. C'est peut-être spécifique au compilateur. Vérifiez donc votre code assembleur produit.

client
la source
-1

Je ne sais pas si j'ai raison mais à mon avis, appeler #define valeur d est beaucoup plus rapide que d'appeler toute autre variable normalement déclarée (ou valeur const). C'est parce que lorsque le programme est en cours d'exécution et qu'il doit utiliser une variable normalement déclarée, il doit sauter à l'endroit exact en mémoire pour obtenir cette variable.

En revanche, lorsqu'il utilise la #definevaleur d, le programme n'a pas besoin de passer à la mémoire allouée, il prend simplement la valeur. Si #define myValue 7et le programme appelant myValue, il se comporte exactement de la même manière que lorsqu'il appelle simplement 7.

pajczur
la source