Quelle est la différence entre une macro et une const en C++?

cette question m'a été posée lors d'un entretien technique:

Quelle est la différence entre un const et une macro en C++?

ma réponse est qu'une macro est une directive préprocesseur et qu'il peut être difficile de déboguer l'application si vous utilisez une macro car elle est remplacée par l'expression constante avant compilation, alors qu'une const peut avoir un identifiant de type et est facile à déboguer.

Quelqu'un pourrait-il indiquer une autre différence et laquelle devrait être préférée?

EDIT:

de la documentation IBM pour C++:

voici quelques différences entre le qualificatif de type #define et le qualificatif de type const :"

  1. la directive #define peut être utilisée pour créer un nom pour un constante numérique, de caractère ou de chaîne, alors qu'un objet const de n'importe quel type peut être déclaré.

  2. un objet const est soumis aux règles d'établissement de la portée pour les variables, alors qu'une constante créée en utilisant #define ne l'est pas. Contrairement à un objet const , la valeur d'une macro n'apparaît pas dans le code source intermédiaire utilisé par le compilateur car ils sont développés en ligne. L'extension inline rend la macro indisponible pour le débogueur.

  3. une macro peut être utilisée dans une expression constante, comme un tableau lié, alors qu'un objet const ne peut pas. (Je pense que nous avons certainement besoin d'utiliser la macro pour définir array_size .

  4. le compilateur ne tape pas-vérifiez une macro, y compris les arguments macro.

19
demandé sur Jamal 2011-06-18 08:04:54

8 réponses

les Macros et les constantes ne sont pas la même chose, chacune est parfois appropriée aux circonstances, et votre réponse ne fait que rayer à la surface de la différence. De plus, C++ a deux types différents de constantes.

une constante définie avec le qualificatif const vaut mieux être considérée comme une non modifiable variable . Il a toutes les propriétés d'une variable: elle a un type, il a une taille, il a lien, vous pouvez prendre à son adresse. (Le compilateur peut optimiser certaines de ces propriétés s'il peut s'en tirer: par exemple, des constantes dont l'adresse n'est jamais utilisée peuvent ne pas être émises dans l'image exécutable. Mais ce n'est que par la grâce du comme-si la règle. La seule chose que vous ne pouvez pas faire à un const est de changer sa valeur. Une constante définie par enum est un peu différente. Il a un type et une taille, mais il n'a pas de lien, vous ne pouvez pas prendre son adresse, et son type est unique. Tous les deux sont traités pendant la phase de traduction 7, donc ils ne peuvent pas être autre chose qu'une valeur L ou une valeur R. (Je suis désolé pour le jargon de la phrase précédente, mais je devrais écrire plusieurs paragraphes sinon.)

une macro a beaucoup moins de contraintes: elle peut s'étendre à n'importe quelle séquence de jetons, aussi longtemps que le programme global reste un programme bien formé. Il n'a aucune des propriétés d'une variable. Appliquer sizeof ou & à une macro peut ou ne peut pas faire quelque chose d'utile, selon ce que la macro étend à. Les Macros sont parfois définies pour s'étendre aux littérales numériques, et ces macros sont parfois pensée de comme des constantes, mais ils ne sont pas: "le compilateur proprement dit" (c'est-à-dire, la phase de traduction 7) les voit comme littérales numériques .

il est généralement considéré comme une bonne pratique, de nos jours, de ne pas utiliser une macro quand une constante fera l'affaire. Les Macros n'obéissent pas aux mêmes règles de cadrage que tous les autres identificateurs, ce qui peut être déroutant, et si vous utilisez une constante, vous donnez plus d'informations à la phase de traduction 7 et donc aussi au débogueur. Cependant, les macros vous permettent de faire des choses qui ne peuvent pas être faites autrement, et si vous avez besoin de faire une de ces choses, vous ne devriez pas hésiter à les utiliser. (Macros qui tirent leur poids, dans ce sens, font généralement pas juste étendre à littérales numériques, bien que je suis ne va pas dire jamais.)

EDIT: voici un exemple de macro faisant quelque chose d'intéressant. Il n'est en aucune façon, forme ou forme une constante. Il pourrait bien y avoir un moyen d'obtenir le même effet sans macro (si vous en connaissez une qui n'implique pas stringstream, je serais curieux d'en entendre parler!) mais je pense qu'il donne une bonne illustration de la puissance et du danger des macros (pour ces derniers, considérez ce qu'il ferait s'il était utilisé en dehors d'un contexte très spécifique...)

static double elapsed()
{ ... }
#define ELAPSED '[' << std::fixed << std::setprecision(2) << elapsed() << "] "

// usage:
for (vector<string>::iterator f = files.begin(); f != files.end(); f++) {
    cout << ELAPSED << "reading file: " << *f << '\n';
    process_file(*f);
}
24
répondu zwol 2011-06-22 20:29:29

on devrait préférer const int sum = 1; à #define sum 1 pour plusieurs raisons:

Mécanisme Fondé Sur La Portée:

#define s ne respectent pas les portées, il n'y a donc aucun moyen de créer un espace de noms de classe. Tandis que les variables de const peuvent être scopées dans les classes.

Eviter les nombres magiques bizarres pendant les erreurs de compilation:

si vous utilisez #define ceux-ci sont remplacés par le pré-processeur au moment de la précompilation donc si vous recevez une erreur lors de la compilation, ce sera déroutant parce que le message d'erreur ne référera pas le nom de la macro mais la valeur et il apparaîtra une valeur soudaine, et on perdrait beaucoup de temps à le traquer en code.

facilité de débogage:

Aussi pour les mêmes raisons, tout en déboguant #define ne fournirait aucune aide vraiment.

Pour éviter les deux situations ci-dessus const sera un meilleur choix.

12
répondu Alok Save 2011-06-18 04:13:47

une autre différence est qu'une variable const a une mémoire et peut être référencée par un pointeur. Macro est juste le autocomplete qui se produira avant la compilation, donc le nom est perdu pendant la compilation.

aussi macro peut être juste plus qu'une constante. Il peut être suis d'expression ou tout ce qui est syntaxiquement correct, même l'ensemble de définition d'une fonction.

Les Macros

sont utilisées pour décrire la programmation les choix, par exemple la taille de la pile; tandis que cosnt est utilisé pour décrire les constantes du monde réel comme la valeur de Pi ou E.

2
répondu Xolve 2011-06-18 04:39:34

(posté à l'origine pour const statique vs #define - reproduit ici car cette question semble avoir plus de"momentum"... permettez-moi de savoir si c'est inapproprié... )

pour et contre à tout, selon l'usage:

  • consts
    • correctement portée / l'identificateur de choc questions traitées joliment
    • fort, simple, du type spécifié par l'utilisateur
      • vous pourriez essayer de" type "a #define ala #define S std::string("abc") , mais la constante évite la construction répétée de temporels distincts à chaque point d'utilisation
    • une règle de définition complications
    • peut prendre l'adresse, créer des références const à eux, etc.
  • définit
    • "" portée globale / plus sujettes à des conflits d'usages, qui peuvent produire des problèmes de compilation difficiles à résoudre et des résultats d'exécution inattendus plutôt que des messages d'erreur sains; pour les atténuer, il faut:
      • identificateurs longs, obscurs et/ou coordonnés au niveau central, et l'accès à ceux-ci ne peut pas bénéficier de la correspondance implicite used/current/Koenig-searched-namespace, namespace aliases etc.
      • l'utilisation de tous les caractères majuscules est généralement requise et réservée au préprocesseur définit (une ligne directrice importante pour l'utilisation des préprocesseurs à l'échelle de l'entreprise doit rester gérable, et on peut s'attendre à ce que les bibliothèques tierces suivent), dont l'observation implique la migration des consts ou des enum existants vers definition implique un changement de la capitalisation (et donc affecte le code client). (Personnellement, je capitalise la première lettre d'enums mais pas consts, donc je serais frappé ici de toute façon - peut-être le temps de repenser cela.)
    • plus d'opérations de compilation possibles: chaîne de caractères concaténation littérale, stringification (compte tenu de leur dimension))
      • l'inconvénient est que donné #define X "x" et une certaine utilisation client ala "pre" X "post" , vous êtes en difficulté si vous voulez ou avez besoin de faire X une variable runtime-changeable plutôt qu'une constante, alors que cette transition est plus facile à partir d'un const char* ou const std::string étant donné qu'ils forcent déjà l'utilisateur à intégrer des opérations de concaténation.
    • ne peut pas utiliser sizeof directement sur une constante numérique définie
    • non typé (GCC ne pas avertir en cas de rapport non signé)
    • certaines chaînes compilateur/linker/debugger ne présentent pas l'identifiant, vous serez donc réduit à regarder "magic numbers" (chaînes, peu importe...)
    • ne peut pas prendre l'adresse
    • la valeur substituée n'a pas besoin d'être légale (ou discrète) dans le contexte où le # define est créé, car il est évalué à chaque point d'utilisation, de sorte que vous pouvez faire référence à des objets non encore déclarés, dépend de "l'implémentation" qui n'a pas besoin d'être pré-inclus, créer des "constantes" telles que { 1, 2 } qui peuvent être utilisées pour initialiser des tableaux, ou #define MICROSECONDS *1E-6 etc. ( certainement ne la recommande pas!)
    • certaines choses spéciales comme __FILE__ et __LINE__ peuvent être intégrées dans la macro substitution
  • enums
    • seulement possible pour les valeurs entières
    • correctement portée / l'identificateur de choc questions traitées joliment
    • fortement dactylographié, mais à une taille int signée-ou-non signée assez grande sur laquelle vous n'avez aucun contrôle (en C++03)
    • ne peut pas prendre l'adresse
    • usage restreint renforcé (p.ex. incrementing - template <typename T> void f(T t) { cout << ++t; } won't compile)
    • type de chaque constante tiré de l'enveloppe enum, donc template <typename T> void f(T) obtenir une instantiation distincte quand passé la même valeur numérique de différents enums, tous qui sont distincts de n'importe quelle instantiation F(int) réelle.
    • même avec typeof, ne peut pas s'attendre numeric_limits à fournir un aperçu utile des
    • le nom-type de l'enum peut apparaître à différents endroits dans RTTI, dans les messages de compilateurs, etc. - peut-être utile, peut-être obfuscation

en tant que règle générale, j'utilise consts et les considère l'option la plus professionnelle pour l'usage général (bien que les autres ont une simplicité attirant à ce vieux programmeur paresseux).

2
répondu Tony Delroy 2017-05-23 12:34:33
Les Macros

ne respectent pas scope, et le nom d'une macro peut ne pas être disponible pour un débogueur symbolique. Dan Saks a un article assez complet sur les mérites relatifs des macros (Aucun), les objets constants, et les constantes d'énumération. Comme Stephen Dewhurst , Saks préfère les constantes d'énumération pour les valeurs entières puisqu'elles ne prennent pas de stockage (plus précisément, les constantes d'énumération n'ont ni durée de stockage ni lien).

0
répondu Gnawme 2011-06-18 05:19:10

définir peut être redéfinir , mais const sera la cause d'erreur du compilateur:

échantillon: source : principal.cpp

#define int_constance 4
#define int_constance 8 // ok, compiler will warning ( redefine macro)

const int a = 2;
const int a = 4; // redefine -> error

int main(int argc, char** argv)
{
   std::cout << int_constance ; // if remove second #define line, output will be 8

   return 0;
}
0
répondu Phạm Mạnh 2014-09-29 16:56:11

Macro comme #define et const les deux sont utilisés dans le langage de programmation C pour définir les constantes.

voyons la différence entre # define et const:

#define

  1. #define est une directive préprocesseur.
  2. #define ne peut définir que la constante simple.

const

  1. const la variable est exactement comme une variable normale en langage C.
  2. const peut aussi définir des constantes complexes.

pour la différence complète: différence entre #define et const en C

0
répondu Shadab Kazi 2018-09-20 06:43:24

une macro a toujours un type, par exemple #define FIVE 5 est de type int.

un avantage pour la variable const par rapport à la macro pourrait être l'utilisation de la mémoire : avec une macro la valeur peut devoir être dupliquée partout où elle est utilisée si une variable const ne sera pas dupliquée en mémoire. (mais je ne suis pas sûr de cette différence)

-1
répondu BenjaminB 2011-06-18 04:16:58