76 votes

Ce sont des C macros utiles pour?

J'ai écrit un peu de C, et je peux le lire assez bien pour obtenir une idée générale de ce qu'il est en train de faire, mais à chaque fois j'ai rencontré une macro, il a jeté moi complètement. Je finis par avoir à se souvenir de ce que la macro est un et remplacer dans ma tête que j'ai lu. Ceux que j'ai rencontrés, qui ont été intuitive et facile à comprendre étaient toujours comme de mini-fonctions, donc je me suis toujours demandé pourquoi ils ne sont pas seulement des fonctions.

Je peux comprendre la nécessité de définir les différents types de débogage ou de la croix-plate-forme s'appuie dans le préprocesseur, mais la possibilité de définir arbitraire des substitutions semble être utile seulement pour faire de, déjà difficile langue encore plus difficile à comprendre.

Pourquoi une telle complexe de préprocesseur introduit pour C? Et quelqu'un aurait-il un exemple d'utilisation qui va me faire comprendre pourquoi il semble toujours être utilisée à des fins autres que de simples si #debug style conditionnel compilations?

Edit:

Après avoir lu un certain nombre de réponses que j'ai encore tout simplement pas l'obtenir. La réponse la plus commune est de code en ligne. Si le mot-clé inline ne pas le faire alors soit il a une bonne raison de ne pas le faire, ou de la mise en œuvre des besoins de fixation. Je ne comprends pas pourquoi d'un tout autre mécanisme est nécessaire que signifie "vraiment inline ce code" (à part la forme du code, écrite avant inline a autour). Aussi je ne comprends pas l'idée qui a été mentionné que "si le son est trop bête pour être mis dans une fonction". Sûrement n'importe quel morceau de code qui prend en entrée et produit une sortie est mieux le mettre dans une fonction. Je pense que j'ai peut-être parce que je ne suis pas habitué à la micro-optimisations de la rédaction de C, mais le préprocesseur se sent juste comme une solution à quelques problèmes simples.

55voto

Pete Kirkham Points 32484

Je finis par avoir à se souvenir de ce que la macro est un et remplacer dans ma tête que j'ai lu.

Qui semble refléter mal sur les noms de macros. Je suppose que vous ne voudriez pas avoir à imiter le préprocesseur si c'était un log_function_entry() macro.

Ceux que j'ai rencontrés, qui ont été intuitive et facile à comprendre étaient toujours comme de mini-fonctions, donc je me suis toujours demandé pourquoi ils ne sont pas seulement des fonctions.

Habituellement, ils devraient être, à moins qu'ils besoin pour fonctionner sur les paramètres génériques.

#define max(a,b) ((a)<(b)?(b):(a))

fonctionne sur n'importe quel type avec un < de l'opérateur.

Bien plus que de simplement les fonctions, macros vous permettent d'effectuer des opérations à l'aide des symboles dans le fichier source. Cela signifie que vous pouvez créer un nouveau nom de variable ou de référence le fichier source et le numéro de ligne de la macro est sur.

En C99, les macros vous permettent également de faire appel variadic fonctions comme printf

#define log_message(guard,format,...) \
   if (guard) printf("%s:%d: " format "\n", __FILE__, __LINE__,__VA_ARGS_);

log_message( foo == 7, "x %d", x)

Dans lequel le format des œuvres comme le printf. Si la garde est vrai, il affiche le message avec le fichier et le numéro de ligne qui a imprimé le message. Si c'était un appel de fonction, il ne serait pas savoir le fichier et la ligne que vous appelé, et à l'aide d'un vaprintf serait un peu plus de travail.

19voto

Brad Gilbert Points 12724

Cet extrait résume assez bien mon avis sur la question, en comparant plusieurs manières C macros sont utilisées, et comment les mettre en œuvre, en D.

copié à partir de DigitalMars.com

De retour lors de l' C a été inventé, compilateur la technologie était primitive. L'installation d'un le texte de la macro du préprocesseur sur le devant la fin était un simple et facile pour ajouter de nombreuses fonctionnalités puissantes. L' l'augmentation de la taille et de la complexité de les programmes ont démontré que ces caractéristiques de venir avec de nombreux inhérente problèmes. D n'ont pas de préprocesseur; mais D fournit un plus évolutive pour résoudre le même problèmes.

Les Macros

Les macros du préprocesseur ajouter de puissantes fonctionnalités et de souplesse à l' C. Mais ils ont un inconvénient:

  • Les Macros n'ont aucune idée de la portée; ils sont valables à partir du point de la définition à la fin de la source. Ils ont coupé un chemin à travers .h fichiers, le code imbriqué, etc. Lors de l' #include'ing des dizaines de milliers de lignes de définitions de macro, il devient problématique afin d'éviter toute expansion des macros.
  • Les Macros sont inconnus pour le débogueur. Essayez de déboguer un programme avec des données symboliques est minée par le débogueur seulement de savoir à propos de l'expansion des macros, pas les macros eux-mêmes.
  • Les Macros font qu'il est impossible de marquer le code source, comme précédemment macro changement peut être arbitrairement refaire jetons.
  • L'purement textuelle de base des macros mène à l'arbitraire et incohérente utilisation, rendre le code à l'aide des macros sujettes à erreur. (Certains tentent de résoudre ce a été introduit avec des modèles en C++.)
  • Les Macros sont encore utilisés pour compenser les déficits dans le langage expressif de capacité, comme pour "wrappers" autour des fichiers d'en-tête.

Voici une énumération des usages communs pour les macros, et la fonction correspondante dans D:

  1. Définition des constantes littérales:

    • L' C Préprocesseur Façon

      #define VALUE 5
      
    • L' D Moyen

      const int VALUE = 5;
      
  2. Création d'une liste de valeurs ou de drapeaux:

    • L' C Préprocesseur Façon

      int flags:
      #define FLAG_X  0x1
      #define FLAG_Y  0x2
      #define FLAG_Z  0x4
      ...
      flags |= FLAG_X;
      
    • L' D Moyen

      enum FLAGS { X = 0x1, Y = 0x2, Z = 0x4 };
      FLAGS flags;
      ...
      flags |= FLAGS.X;
      
  3. Fonction d'établissement des conventions d'appel:

    • L' C Préprocesseur Façon

      #ifndef _CRTAPI1
      #define _CRTAPI1 __cdecl
      #endif
      #ifndef _CRTAPI2
      #define _CRTAPI2 __cdecl
      #endif
      
      
      int _CRTAPI2 func();
      
    • L' D Moyen

      Les conventions d'appel peut être spécifié dans les blocs, donc il n'y a pas besoin de le changer pour chaque fonction:

      extern (Windows)
      {
          int onefunc();
          int anotherfunc();
      }
      
  4. Simple de programmation générique:

    • L' C Préprocesseur Façon

      La sélection de la fonction à utiliser en fonction de remplacement de texte:

      #ifdef UNICODE
      int getValueW(wchar_t *p);
      #define getValue getValueW
      #else
      int getValueA(char *p);
      #define getValue getValueA
      #endif
      
    • L' D Moyen

      D permet aux déclarations de symboles qui sont des alias d'autres symboles:

      version (UNICODE)
      {
          int getValueW(wchar[] p);
          alias getValueW getValue;
      }
      else
      {
          int getValueA(char[] p);
          alias getValueA getValue;
      }
      

Il y a plus d'exemples sur les DigitalMars site web.

16voto

fortran Points 26495

Ils sont un langage de programmation (un plus simple) sur le dessus de C, de sorte qu'ils sont utiles pour faire de la métaprogrammation au moment de la compilation... en d'autres termes, vous pouvez écrire le code de macro qui génère du code C en moins de lignes et le temps qu'il faudra l'écrire directement en C.

Ils sont également très utiles pour écrire "fonctionnent comme des" expressions "polymorphe" ou "surchargé"; par exemple, un max de macro définie comme:

#define max(a,b) ((a)>(b)?(a):(b))

est utile pour tout type numérique; et C vous ne pourriez pas écrire:

int max(int a, int b) {return a>b?a:b;}
float max(float a, float b) {return a>b?a:b;}
double max(double a, double b) {return a>b?a:b;}
...

même si tu le voulais, parce que vous ne pouvez pas la surcharge de fonctions.

Et pour ne pas mentionner de compilation conditionnelle et de fichiers, y compris (qui font aussi partie de la macro-langage)...

12voto

hdante Points 2192

Les Macros permettent à quelqu'un de modifier le comportement du programme lors de la compilation. Réfléchissez à ceci:

  • C des constantes de permettre la fixation de comportement d'un programme à temps de développement
  • C variables permettent de modifier le comportement du programme au moment de l'exécution
  • C macros permettent de modifier le comportement du programme au moment de la compilation

Au moment de la compilation signifie que le code inutilisé ne vais même pas dans le binaire et que le processus de construction peut modifier les valeurs, tant qu'il est intégré avec la macro du préprocesseur. Exemple: make ARCH=arm (ce qui suppose que la redirection de définition de macro cc -DARCH=arm)

Exemples simples: (depuis la glibc limites.h, de définir la valeur la plus grande de long)

#if __WORDSIZE == 64
#define LONG_MAX 9223372036854775807L
#else
#define LONG_MAX 2147483647L
#endif

Vérifie (en utilisant le #define __WORDSIZE) au moment de la compilation, si nous sommes de la compilation de 32 ou 64 bits. Avec un multilib de la chaîne, à l'aide des paramètres -m32 et -m64 peut automatiquement changer de taille en bits.

(POSIX demande de version)

#define _POSIX_C_SOURCE 200809L

Les demandes lors de la compilation du temps POSIX soutien de 2008. La bibliothèque standard peut supporter de nombreux (incompatibles), les normes, mais avec cette définition, il fournira la bonne prototypes de fonction (exemple: getline(), pas de gets(), etc.). Si la bibliothèque ne prend pas en charge la norme, il peut donner une #erreur lors de la compilation, au lieu de s'écraser lors de l'exécution, par exemple.

(codé en dur le chemin d'accès)

#ifndef LIBRARY_PATH
#define LIBRARY_PATH "/usr/lib"
#endif

Définit, lors de la compilation du temps a coder en dur annuaire. Peut être changé avec -DLIBRARY_PATH=/home/utilisateur/lib, par exemple. Si c'était un const char *, comment voulez-vous configurer lors de la compilation ?

(pthread.h, des définitions complexes au moment de la compilation)

# define PTHREAD_MUTEX_INITIALIZER \
  { { 0, 0, 0, 0, 0, 0, { 0, 0 } } }

De gros morceaux de texte qui, autrement, ne serait pas simplifié peut être déclaré (toujours au moment de la compilation). Il n'est pas possible de le faire avec des fonctions ou des constantes (au moment de la compilation).

Pour éviter de vraiment compliquer les choses et pour éviter de suggérer un mauvais codage des styles, je suis à la coutume de donner un exemple de code qui compile différentes, incompatibles, les systèmes d'exploitation. Utilisez votre croix de construction du système, mais il doit être clair que le préprocesseur permet que sans l'aide de la construction du système, sans rupture de la compilation en raison de l'absence d'interfaces.

Enfin, pensez à l'importance de la compilation conditionnelle sur des systèmes embarqués, où la vitesse du processeur et de la mémoire sont limitées et les systèmes sont très hétérogènes.

Maintenant, si vous demandez, est-il possible de remplacer tous les macro définitions de constantes et des appels de fonction avec une bonne définitions ? La réponse est oui, mais il ne sera pas tout simplement faire le nécessaire pour le changement de comportement d'un programme lors de la compilation de s'en aller. Le préprocesseur serait encore nécessaire.

11voto

Michael Kohne Points 8233

Rappelez-vous que les macros (et le pré-processeur) venir dès les premiers jours de C. Ils ont utilisé pour être le SEUL moyen de faire inline 'fonctions' (parce que, bien sûr, inline est très récente mot-clé), et ils sont encore le seul moyen de faire quelque chose pour être incorporé.

Aussi, les macros sont la seule façon que vous pouvez faire ces trucs que l'insertion du fichier et la ligne en constantes de chaîne au moment de la compilation.

Ces jours-ci, beaucoup de choses que les macros utilisé pour être la seule façon de le faire sont mieux traitées par le biais de nouveaux mécanismes. Mais ils ont encore leur place, de temps à autre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X