Question

J'ai écrit un peu de C et je le lis assez bien pour avoir une idée générale de ce qu'il fait, mais chaque fois que j'ai rencontré une macro, cela m'a complètement jeté. . Je finis par devoir me rappeler ce qu'est la macro et la substituer dans ma tête au fur et à mesure que je lisais. Celles que j’ai rencontrées, intuitives et faciles à comprendre, ressemblaient toujours à de petites mini-fonctions. Je me suis donc toujours demandé pourquoi elles n’étaient pas que des fonctions.

Je peux comprendre la nécessité de définir différents types de construction pour les versions de plate-forme de débogage ou inter-plateformes dans le pré-processeur, mais la possibilité de définir des substitutions arbitraires semble utile uniquement pour rendre un langage déjà difficile encore plus difficile à comprendre.

Pourquoi un préprocesseur aussi complexe a-t-il été introduit pour C ? Et est-ce que quelqu'un a un exemple d'utilisation qui me fera comprendre pourquoi il semble toujours être utilisé à des fins autres que simples si des compilations conditionnelles de style #debug?

Modifier:

Après avoir lu un certain nombre de réponses, je ne comprends toujours pas. La réponse la plus courante consiste à utiliser du code en ligne. Si le mot clé en ligne ne le fait pas, il a soit une bonne raison de ne pas le faire, soit la mise en œuvre doit être corrigée. Je ne comprends pas pourquoi un mécanisme complètement différent est nécessaire, ce qui signifie & "Vraiment en ligne ce code &"; (à part le code écrit avant qu'Inline ne soit là). Je ne comprends pas non plus l’idée mentionnée selon laquelle & «S’il est trop bête d’être inséré dans une fonction &». Il est certainement préférable de placer une fonction dans un morceau de code prenant une entrée et produisant une sortie. Je pense ne pas comprendre, car je ne suis pas habitué aux microoptimisations de l'écriture C , mais le préprocesseur semble être une solution complexe à quelques problèmes simples.

Était-ce utile?

La solution

  

Je finis par devoir me souvenir de la macro et la remplacer dans ma tête au fur et à mesure que je lisais.

Cela semble nuire à la dénomination des macros. Je suppose que vous n’auriez pas à émuler le préprocesseur s’il s’agissait d’une macro log_function_entry().

  

Ceux que j’ai rencontrés qui étaient intuitifs et faciles à comprendre ressemblaient toujours à de petites fonctions mini. Je me suis donc toujours demandé pourquoi ils n’étaient que des fonctions.

Habituellement, ils devraient l'être, à moins qu'ils n'aient besoin d'opérer sur des paramètres génériques.

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

travaillera sur tout type avec un < opérateur.

Plus que de simples fonctions, les macros vous permettent d'effectuer des opérations en utilisant les symboles du fichier source. Cela signifie que vous pouvez créer un nouveau nom de variable ou référencer le fichier source et le numéro de ligne sur lequel se trouve la macro.

En C99, les macros vous permettent également d’appeler des fonctions variadiques telles que 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 fonctionne comme printf. Si la valeur de garde est vraie, il envoie le message avec le fichier et le numéro de ligne qui l'a imprimé. S'il s'agissait d'un appel de fonction, il ne connaîtrait pas le fichier ni la ligne depuis laquelle vous l'avez appelé, et utiliser un vaprintf serait un peu plus de travail.

Autres conseils

Cet extrait résume assez bien mon point de vue sur le sujet, en comparant plusieurs façons dont les C macros sont utilisées et la façon de les implémenter dans D.

copié de DigitalMars.com

  

À l'époque où #include a été inventé, compilateur   la technologie était primitive. Installer un   préprocesseur de macro de texte sur le devant   fin était un moyen simple et direct   d'ajouter de nombreuses fonctionnalités puissantes. le   taille croissante & amp; complexité de   les programmes ont montré que ces   les fonctionnalités viennent avec de nombreux inhérents   problèmes. C++ n'a pas de   pré-processeur; mais <=> fournit un plus   des moyens évolutifs pour résoudre le même   problèmes.

Macros

Les macros de préprocesseur ajoutent des fonctionnalités puissantes et de la souplesse à <=>. Mais ils ont un inconvénient:

  • Les macros n'ont pas de concept de portée. ils sont valables du point de définition à la fin de la source. Ils coupent la bande entre les fichiers .h, le code imbriqué, etc. Lorsque vous <=> 'définissez des dizaines de milliers de lignes de définitions de macros, il devient problématique d'éviter des extensions de macros par inadvertance.
  • Les macros sont inconnues du débogueur. Tenter de déboguer un programme avec des données symboliques est compromis par le fait que le débogueur ne connaît que les extensions de macros, pas les macros elles-mêmes.
  • Les macros rendent impossible la création de code pour le code source, puisqu'un changement de macro précédent peut rétablir arbitrairement des jetons.
  • La base purement textuelle des macros conduit à une utilisation arbitraire et incohérente, rendant le code source d’erreurs. (Certaines tentatives pour résoudre ce problème ont été introduites avec des modèles dans <=>.)
  • Les
  • macros sont toujours utilisées pour compenser les déficits de la capacité d'expression du langage, comme pour les & "; wrappers &"; autour des fichiers d'en-tête.

Voici une énumération des utilisations courantes des macros et la fonctionnalité correspondante dans D:

  1. Définition des constantes littérales:

    • La <=> méthode de préprocesseur

      #define VALUE 5
      
    • La <=> manière

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

    • La <=> méthode de préprocesseur

      int flags:
      #define FLAG_X  0x1
      #define FLAG_Y  0x2
      #define FLAG_Z  0x4
      ...
      flags |= FLAG_X;
      
    • La <=> manière

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

    • La <=> méthode de préprocesseur

      #ifndef _CRTAPI1
      #define _CRTAPI1 __cdecl
      #endif
      #ifndef _CRTAPI2
      #define _CRTAPI2 __cdecl
      #endif
      
      int _CRTAPI2 func();
      
    • La <=> manière

      Les conventions d’appel peuvent être spécifiées dans des blocs, il n’est donc pas nécessaire de les changer pour chaque fonction:

      extern (Windows)
      {
          int onefunc();
          int anotherfunc();
      }
      
  4. Programmation générique simple:

    • La <=> méthode de préprocesseur

      Sélection de la fonction à utiliser en fonction de la substitution de texte:

      #ifdef UNICODE
      int getValueW(wchar_t *p);
      #define getValue getValueW
      #else
      int getValueA(char *p);
      #define getValue getValueA
      #endif
      
    • La <=> manière

      <=> active les déclarations de symboles alias d'autres symboles:

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

Il existe d’autres exemples sur le site Web DigitalMars .

C’est un langage de programmation (plus simple) au-dessus de C; ils sont donc utiles pour effectuer des métaprogrammations au moment de la compilation. En d’autres termes, vous pouvez écrire du code macro qui génère du code C en moins de lignes et de temps. il faudra l'écrire directement en C.

Ils sont également très utiles pour écrire & "fonction comme &"; expressions qui sont " polymorphes " ou " surchargé " ;; par exemple. une macro max définie comme:

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

est utile pour tout type numérique; et en C vous ne pouviez 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 vous le souhaitiez, car vous ne pouvez pas surcharger les fonctions.

Et pour ne pas mentionner la compilation conditionnelle et le fichier incluant (qui font également partie du langage macro) ...

Les macros permettent à quelqu'un de modifier le comportement du programme pendant la compilation. Considérez ceci:

  • Les constantes C permettent de corriger le comportement du programme au moment du développement
  • Les variables C permettent de modifier le comportement du programme au moment de l'exécution
  • Les macros C permettent de modifier le comportement du programme au moment de la compilation

Au moment de la compilation, cela signifie que le code non utilisé ne sera même pas inséré dans le fichier binaire et que le processus de construction peut modifier les valeurs, à condition qu'il soit intégré au préprocesseur de macro. Exemple: make ARCH = arm (en supposant que la définition de macro de transfert soit cc -DARCH = arm)

Exemples simples: (à partir de la glibc limits.h, définissez la plus grande valeur de long)

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

Vérifie (en utilisant le #define __WORDSIZE) à la compilation si nous compilons pour 32 ou 64 bits. Avec une chaîne d’outils multilib, l’utilisation des paramètres -m32 et -m64 peut changer automatiquement la taille des bits.

(demande de version POSIX)

#define _POSIX_C_SOURCE 200809L

Demandes pendant la compilation Prise en charge de POSIX 2008. La bibliothèque standard peut prendre en charge de nombreux standards (incompatibles), mais avec cette définition, elle fournira les prototypes de fonctions corrects (exemple: getline (), no gets (), etc.). Si la bibliothèque ne prend pas en charge le standard, elle peut générer une erreur # lors de la compilation, au lieu de se bloquer lors de l'exécution, par exemple.

(chemin codé en dur)

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

Définit, pendant la compilation, un répertoire hardcode. Pourrait être changé avec -DLIBRARY_PATH = / home / user / lib, par exemple. S'il s'agissait d'un caractère const *, comment le configureriez-vous lors de la compilation?

(pthread.h, définitions complexes à la compilation)

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

Les gros morceaux de texte peuvent être déclarés (toujours au moment de la compilation) sans être simplifiés. Cela n'est pas possible avec des fonctions ou des constantes (au moment de la compilation).

Pour éviter de vraiment compliquer les choses et pour éviter de suggérer des styles de codage médiocres, je ne donnerai pas d'exemple de code compilé sous différents systèmes d'exploitation incompatibles. Utilisez votre système cross-build pour cela, mais il devrait être clair que le pré-processeur le permet sans l'aide du système de compilation, sans interrompre la compilation en raison d'interfaces absentes.

Enfin, réfléchissez à l’importance de la compilation conditionnelle sur les systèmes intégrés, où la vitesse du processeur et la mémoire sont limitées et les systèmes très hétérogènes.

Maintenant, si vous le demandez, est-il possible de remplacer toutes les définitions de constante de macro et les appels de fonction par les définitions appropriées? La réponse est oui, mais cela ne fera pas disparaître la nécessité de changer le comportement du programme pendant la compilation. Le préprocesseur serait toujours nécessaire.

N'oubliez pas que les macros (et le pré-processeur) proviennent des premiers jours de C. Ils étaient auparavant le SEUL moyen de créer des "fonctions" en ligne (car, bien entendu, inline est un mot clé très récent). sont toujours le seul moyen de forcer quelque chose à être en ligne.

De plus, les macros sont le seul moyen de réaliser des astuces telles que l’insertion du fichier et de la ligne dans les constantes de chaîne au moment de la compilation.

De nos jours, la plupart des choses que les macros étaient auparavant le seul moyen de faire sont mieux gérées par le biais de mécanismes plus récents. Mais ils ont toujours leur place, de temps en temps.

Hormis l'inline pour l'efficacité et la compilation conditionnelle, les macros peuvent être utilisées pour augmenter le niveau d'abstraction du code C de bas niveau. C ne vous isole pas vraiment des détails essentiels de la gestion de la mémoire et des ressources, ni de la présentation exacte des données, et ne prend en charge que des formes très limitées de masquage d'informations et d'autres mécanismes de gestion de grands systèmes. Avec les macros, vous n'êtes plus obligé d'utiliser uniquement les constructions de base en langage C: vous pouvez définir vos propres structures de données et constructions de codage (y compris les classes et les modèles!) Tout en écrivant nominalement C!

Les macros de préprocesseur offrent en réalité une langue Turing-complete exécutée au moment de la compilation. L’un des exemples impressionnants (et légèrement effrayants) de ce phénomène est du côté C ++: le Boost Preprocessor utilise la bibliothèque C99 / C ++ 98 pré-processeur pour construire des constructions de programmation (relativement) sûres qui sont ensuite étendues à toutes les déclarations sous-jacentes et le code que vous entrez, que ce soit C ou C ++.

En pratique, je vous conseillerais de ne recourir en dernier recours à la programmation préprocesseur que lorsque vous ne disposez pas de la latitude nécessaire pour utiliser des constructions de haut niveau dans des langues plus sûres. Mais parfois, il est bon de savoir ce que vous pouvez faire si votre dos est contre le mur et que les belettes se referment ...!

De Stupidités de l'ordinateur :

  

J'ai vu cet extrait de code dans de nombreux programmes de jeu gratuits pour UNIX:

     

/ *
   * Valeurs en bits.
   * /
   #define BIT_0 1
   #define BIT_1 2
   #define BIT_2 4
   #define BIT_3 8
   #define BIT_4 16
   #define BIT_5 32
   #define BIT_6 64
   #define BIT_7 128
   #define BIT_8 256
   #define BIT_9 512
   #define BIT_10 1024
   #define BIT_11 2048
   #define BIT_12 4096
   #define BIT_13 8192
   #define BIT_14 16384
   #define BIT_15 32768
   #define BIT_16 65536
   #define BIT_17 131072
   #define BIT_18 262144
   #define BIT_19 524288
   #define BIT_20 1048576
   #define BIT_21 2097152
   #define BIT_22 4194304
   #define BIT_23 8388608
   #define BIT_24 16777216
   #define BIT_25 33554432
   #define BIT_26 67108864
   #define BIT_27 134217728
   #define BIT_28 268435456
   #define BIT_29 536870912
   #define BIT_30 1073741824
   #define BIT_31 2147483648

     

Un moyen beaucoup plus simple d'y parvenir est:

     

#define BIT_0 0x00000001
   #define BIT_1 0x00000002
   #define BIT_2 0x00000004
   #define BIT_3 0x00000008
   #define BIT_4 0x00000010
   ...
   #define BIT_28 0x10000000
   #define BIT_29 0x20000000
   #define BIT_30 0x40000000
   #define BIT_31 0x80000000

     

Un moyen plus simple consiste toujours à laisser le compilateur faire les calculs:

     

#define BIT_0 (1)
   #define BIT_1 (1 < < 1)
   #define BIT_2 (1 < < 2)
   #define BIT_3 (1 < < 3)
   #define BIT_4 (1 < < 4)
   ...
   #define BIT_28 (1 < < 28)
   #define BIT_29 (1 < < 29)
   #define BIT_30 (1 < < 30)
   #define BIT_31 (1 < < 31)

     

Mais pourquoi vous donner la peine de définir 32 constantes? Le langage C dispose également de macros paramétrées. Tout ce dont vous avez vraiment besoin est:

     

#define BIT (x) (1 < < (x))

     

Quoi qu’il en soit, je me demande si le gars qui a écrit le code original a utilisé une calculatrice ou a tout simplement calculé le tout sur papier.

Il ne s'agit que d'une utilisation possible des macros.

L'un des cas où les macros sont vraiment brillantes est la génération de code avec celles-ci.

J'avais l'habitude de travailler sur un ancien système C ++ qui utilisait un système de plug-in avec sa propre façon de transmettre des paramètres au plug-in (Utilisation d'une structure personnalisée de type map). Quelques macros simples ont été utilisées pour pouvoir traiter cette bizarrerie et nous ont permis d'utiliser de vraies classes et fonctions C ++ avec des paramètres normaux dans les plugins sans trop de problèmes. Tout le code de liaison généré par les macros.

Je vais ajouter à ce qui a déjà été dit.

Etant donné que les macros fonctionnent sur les substitutions de texte, elles vous permettent de réaliser des tâches très utiles qu'il serait impossible d'utiliser avec des fonctions.

Voici quelques cas où les macros peuvent être vraiment utiles:

/* Get the number of elements in array 'A'. */
#define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))

Il s’agit d’une macro très populaire et fréquemment utilisée. Ceci est très pratique lorsque, par exemple, vous devez parcourir un tableau.

int main(void)
{
    int a[] = {1, 2, 3, 4, 5};
    int i;
    for (i = 0; i < ARRAY_LENGTH(a); ++i) {
        printf("a[%d] = %d\n", i, a[i]);
    }
    return 0;
}

Ici, peu importe si un autre programmeur ajoute cinq autres éléments à a dans la décleration. La for - boucle toujours parcourt tous les éléments.

Les fonctions de comparaison de la mémoire et des chaînes de la bibliothèque C sont plutôt laides à utiliser.

Vous écrivez:

char *str = "Hello, world!";

if (strcmp(str, "Hello, world!") == 0) {
    /* ... */
}

ou

char *str = "Hello, world!";

if (!strcmp(str, "Hello, world!")) {
    /* ... */
}

Pour vérifier si str pointe vers "Hello, world". Personnellement, je pense que ces deux solutions sont très laides et déroutantes (en particulier !strcmp(...)).

Voici deux macros ordonnées que certaines personnes (y compris I) utilisent lorsqu'elles doivent comparer des chaînes ou de la mémoire à l'aide de strcmp / memcmp:

/* Compare strings */
#define STRCMP(A, o, B) (strcmp((A), (B)) o 0)

/* Compare memory */
#define MEMCMP(A, o, B) (memcmp((A), (B)) o 0)

Vous pouvez maintenant écrire le code comme ceci:

char *str = "Hello, world!";

if (STRCMP(str, ==, "Hello, world!")) {
    /* ... */
}

Voici l'intention beaucoup plus claire!

Ce sont des cas où les macros sont utilisées pour des tâches que les fonctions ne peuvent accomplir. Les macros ne doivent pas être utilisées pour remplacer des fonctions, mais elles ont d’autres utilisations intéressantes.

Étant donné les commentaires de votre question, vous n’allez peut-être pas vraiment comprendre que le fait d’appeler une fonction peut entraîner une surcharge considérable. Il peut être nécessaire de copier les paramètres et les registres de clé dans la pile lors de l’entrée et de la désenrouler lors de la sortie. Cela était particulièrement vrai pour les anciens processeurs Intel. Les macros permettent au programmeur de conserver (presque) l'abstraction d'une fonction, tout en évitant le surcoût coûteux d'un appel de fonction. Le mot clé en ligne est consultatif, mais le compilateur peut ne pas toujours réussir. La gloire et le danger de 'C' est que vous pouvez généralement plier le compilateur à votre guise.

Dans votre pain quotidien, la programmation quotidienne d'applications telle que la micro-optimisation (éviter les appels de fonction) est généralement pire qu'inutile, mais si vous écrivez une fonction à durée critique appelée par le noyau d'un système d'exploitation système, alors il peut faire une énorme différence.

Contrairement aux fonctions habituelles, vous pouvez contrôler le flux (si, tant que, pour, ...) dans les macros. Voici un exemple:

#include <stdio.h>

#define Loop(i,x) for(i=0; i<x; i++)

int main(int argc, char *argv[])
{
    int i;
    int x = 5;
    Loop(i, x)
    {
        printf("%d", i); // Output: 01234
    } 
    return 0;
} 

C'est bon pour le code en ligne et éviter les frais généraux liés aux appels de fonctions. En plus de l'utiliser si vous souhaitez modifier le comportement ultérieurement sans modifier de nombreux lieux. Ce n'est pas utile pour les choses complexes, mais pour les simples lignes de code que vous voulez insérer, ce n'est pas mal.

En exploitant la manipulation de texte du préprocesseur C, il est possible de construire l’équivalent C d’une structure de données polymorphe. En utilisant cette technique, nous pouvons construire une boîte à outils fiable de structures de données primitives pouvant être utilisées dans tout programme C, car elles exploitent la syntaxe C et non les spécificités d'une implémentation particulière.

Des explications détaillées sur l'utilisation des macros pour la gestion de la structure de données sont données ici - http://multi-core-dump.blogspot.com/2010/11/interesting-use-of-c-macros-polymorphic.html

Les macros vous permettent de vous débarrasser des fragments copiés que vous ne pouvez pas éliminer autrement.

Par exemple (le code réel, la syntaxe du compilateur VS 2010):

for each (auto entry in entries)
{
        sciter::value item;
        item.set_item("DisplayName",    entry.DisplayName);
        item.set_item("IsFolder",       entry.IsFolder);
        item.set_item("IconPath",       entry.IconPath);
        item.set_item("FilePath",       entry.FilePath);
        item.set_item("LocalName",      entry.LocalName);
        items.append(item);
    }

Il s'agit de l'endroit où vous passez une valeur de champ sous le même nom dans un moteur de script. Est-ce copié-collé? Oui. DisplayName est utilisé comme chaîne pour un script et comme nom de champ pour le compilateur. Est-ce mauvais? Oui. Si vous refactorisez votre code et renommez LocalName en RelativeFolderName (comme je l'ai fait) et oubliez de faire de même avec la chaîne (comme je l'ai fait), le script fonctionnera d'une manière inattendue (en fait, dans mon exemple, cela dépend de ce que vous avez oublié de renommer le champ dans un fichier de script séparé, mais si le script est utilisé pour la sérialisation, il s'agirait d'un bogue de 100%).

Si vous utilisez une macro pour cela, il n'y aura plus de place pour le bogue:

for each (auto entry in entries)
{
#define STR_VALUE(arg) #arg
#define SET_ITEM(field) item.set_item(STR_VALUE(field), entry.field)
        sciter::value item;
        SET_ITEM(DisplayName);
        SET_ITEM(IsFolder);
        SET_ITEM(IconPath);
        SET_ITEM(FilePath);
        SET_ITEM(LocalName);
#undef SET_ITEM
#undef STR_VALUE
        items.append(item);
    }

Malheureusement, cela ouvre la porte à d'autres types de bugs. Vous pouvez créer une faute de frappe en écrivant la macro et ne jamais voir un code corrompu, car le compilateur n'affiche pas son apparence après le prétraitement. Quelqu'un d’autre pourrait utiliser le même nom (c’est pourquoi & Je libère & Les macros dès que possible avec #undef). Alors, utilisez-le judicieusement. Si vous voyez une autre façon de vous débarrasser du code copié-collé (tel que des fonctions), utilisez cette méthode. Si vous constatez que supprimer le code copié-collé avec des macros ne vaut pas la peine, conservez le code copié-collé.

Une des raisons évidentes est qu’en utilisant une macro, le code sera développé lors de la compilation et vous obtiendrez un pseudo appel de fonction sans la surcharge de l’appel.

Sinon, vous pouvez également l'utiliser pour les constantes symboliques, de sorte que vous n'ayez pas à modifier la même valeur à plusieurs endroits pour modifier une petite chose.

Macros .. pour quand votre & amp; # (* $ & ampli compilateur refuse tout simplement d’aligner quelque chose.

Cela devrait être une affiche de motivation, non?

Sérieusement, Google abus de la part du préprocesseur (vous pouvez voir une question SO similaire comme la question n ° 1 résultat). Si j'écris une macro qui va au-delà des fonctionnalités de assert (), j'essaie généralement de voir si mon compilateur intégrerait réellement une fonction similaire.

D'autres s'opposeront à l'utilisation de #if pour la compilation conditionnelle. Ils préféreraient vous:

if (RUNNING_ON_VALGRIND)

plutôt que

#if RUNNING_ON_VALGRIND

.. à des fins de débogage, puisque vous pouvez voir if () mais pas #if dans un débogueur. Ensuite, nous plongeons dans #ifdef vs #if.

Si son code est inférieur à 10 lignes, essayez de l’aligner. Si ce n'est pas possible, essayez de l'optimiser. Si c'est trop bête pour être une fonction, créez une macro.

Même si je ne suis pas un grand fan des macros et que je n'ai plus tendance à écrire beaucoup de C, sur la base de mes tâches actuelles, quelque chose comme ceci (qui pourrait évidemment avoir des effets secondaires) est pratique:

#define MIN(X, Y)  ((X) < (Y) ? (X) : (Y))

Maintenant, je n’ai rien écrit de la sorte depuis des années, mais les "fonctions" de ce type étaient l’ensemble du code que j’avais maintenu plus tôt dans ma carrière. Je suppose que l’extension pourrait être considérée comme pratique.

Je n'ai vu personne parler de cela, donc, concernant les fonctions comme les macros, par exemple:

#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))

En règle générale, il est recommandé d'éviter l'utilisation de macros lorsque cela n'est pas nécessaire, pour de nombreuses raisons, la lisibilité étant la principale préoccupation. Donc:

  

Quand devriez-vous utiliser ces fonctions sur une fonction?

Presque jamais, puisqu'il existe une alternative plus lisible, inline, voir https://www.greenend.org.uk/rjk/tech/inline.html ou http://www.cplusplus.com/articles/2LywvCM9/ (le deuxième lien est une page C ++, mais le point s’applique aux compilateurs c pour autant que je sache).

Maintenant, la légère différence est que les macros sont gérées par le pré-processeur et inline par le compilateur, mais il n'y a pas de différence pratique de nos jours.

  

quand est-il approprié de les utiliser?

Pour les petites fonctions (deux ou trois liners maximum). L’objectif est d’obtenir un avantage lors de l’exécution d’un programme, car les fonctions telles que les macros (et les fonctions inline) sont des remplacements de code effectués lors du prétraitement (ou une compilation en cas d’inline) et ne sont pas de véritables fonctions vivant en mémoire, il n'y a donc pas de surcharge d'appel de fonction (plus de détails dans les pages liées).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top