Fonctions en ligne vs macros de préprocesseur

Réponses:

127

Les macros de préprocesseur ne sont que des modèles de substitution appliqués à votre code. Ils peuvent être utilisés presque n'importe où dans votre code car ils sont remplacés par leurs extensions avant le début de toute compilation.

Les fonctions en ligne sont des fonctions réelles dont le corps est directement injecté dans leur site d'appel. Ils ne peuvent être utilisés que lorsqu'un appel de fonction est approprié.

Maintenant, en ce qui concerne l'utilisation de macros par rapport aux fonctions en ligne dans un contexte de type fonction, sachez que:

  • Les macros ne sont pas de type sécurisé et peuvent être développées indépendamment du fait qu'elles soient ou non synchroniquement correctes - la phase de compilation rapportera des erreurs résultant de problèmes d'expansion de macro.
  • Les macros peuvent être utilisées dans un contexte où vous ne vous attendez pas, ce qui entraîne des problèmes
  • Les macros sont plus flexibles, en ce sens qu'elles peuvent développer d'autres macros - alors que les fonctions en ligne ne le font pas nécessairement.
  • Les macros peuvent entraîner des effets secondaires en raison de leur expansion, car les expressions d'entrée sont copiées partout où elles apparaissent dans le modèle.
  • Les fonctions en ligne ne sont pas toujours garanties d'être intégrées - certains compilateurs ne le font que dans les versions de version, ou lorsqu'ils sont spécifiquement configurés pour le faire. En outre, dans certains cas, l'inlining peut ne pas être possible.
  • Les fonctions en ligne peuvent fournir une portée pour les variables (en particulier les variables statiques), les macros de préprocesseur ne peuvent le faire que dans des blocs de code {...}, et les variables statiques ne se comportent pas exactement de la même manière.
LBushkin
la source
39
Les fonctions en ligne ne sont pas toujours garanties d'être intégrées: parce que le compilateur ne sera pas en ligne si cela générera du code plus lent, etc. Le compilateur fait beaucoup d'analyses que l'ingénieur ne peut pas et fait la bonne chose.
Martin York
14
Je crois que les fonctions récursives sont un autre exemple où la plupart des compilateurs ignorent l'inlining.
LBushkin
Existe-t-il des différences importantes entre C et C ++ dans ce cas?
rzetterberg le
7
Un point non mentionné est que l'inlining peut être influencé par les indicateurs de compilation. Par exemple, lorsque vous construisez pour une vitesse maximale (comme GCC -O2 / -O3), le compilateur choisira d'insérer de nombreuses fonctions, mais lorsque vous construisez pour une taille minimale (-Os), il sera généralement des fonctions en ligne appelées une seule fois (ou de très petites fonctions ). Avec les macros, ce choix n'existe pas.
dbrank0
Les macros ne peuvent pas couvrir avec le spécificateur d'accès (comme, privé ou protégé) alors que les fonctions en ligne sont possibles.
Hit du
78

Tout d'abord, les macros du préprocesseur sont simplement des "copier-coller" dans le code avant la compilation. Il n'y a donc pas de vérification de type et certains effets secondaires peuvent apparaître

Par exemple, si vous souhaitez comparer 2 valeurs:

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

Les effets secondaires apparaissent si vous utilisez max(a++,b++)par exemple ( aou bseront incrémentés deux fois). À la place, utilisez (par exemple)

inline int max( int a, int b) { return ((a<b)?b:a); }
ThibThib
la source
3
Je veux juste ajouter à votre exemple qu'en plus des effets secondaires, la macro peut également introduire une charge de travail supplémentaire, considérez que max(fibonacci(100), factorial(10000))la plus grande sera calculée deux fois :(
watashiSHUN
Tout le monde parle de vérification de type, mais vous venez de fournir un exemple concret, c'est pourquoi je vote pour cette réponse.
Ivanzinho le
16

La fonction Inline est développée par le compilateur alors que les macros sont développées par le préprocesseur, qui est une simple substitution textuelle.

  • Il n'y a pas de vérification de type lors de l'appel de macro tandis que la vérification de type est effectuée lors de l'appel de fonction.

  • Des résultats indésirables et une inefficacité peuvent survenir lors de l'expansion macro-économique en raison de la réévaluation des arguments et de l'ordre des opérations. Par exemple

    #define MAX(a,b) ((a)>(b) ? (a) : (b))
    int i = 5, j = MAX(i++, 0);
    

    entraînerait

    int i = 5, j = ((i++)>(0) ? (i++) : (0));
  • Les arguments de macro ne sont pas évalués avant le développement de la macro

    #define MUL(a, b) a*b
    int main()
    {
      // The macro is expended as 2 + 3 * 3 + 5, not as 5*8
      printf("%d", MUL(2+3, 3+5));
     return 0;
    }
    // Output: 16`
    
  • Le mot-clé return ne peut pas être utilisé dans les macros pour renvoyer des valeurs comme dans le cas des fonctions.

  • Les fonctions en ligne peuvent être surchargées

  • Les jetons passés aux macros peuvent être concaténés à l'aide de l'opérateur ## appelé opérateur Token-Pasting.

  • Les macros sont généralement utilisées pour la réutilisation de code, alors que les fonctions en ligne sont utilisées pour éliminer la surcharge de temps (temps excessif) pendant l'appel de fonction (évitant un saut vers un sous-programme).

DataCruncher
la source
13

La principale différence est la vérification de type. Le compilateur vérifiera si ce que vous passez en tant que valeurs d'entrée est de types qui peuvent être passés dans la fonction. Ce n'est pas vrai avec les macros de préprocesseur - elles sont développées avant toute vérification de type et cela peut provoquer des bogues graves et difficiles à détecter.

Voici plusieurs autres points moins évidents soulignés.

dents acérées
la source
11

Pour ajouter une autre différence à celles déjà données: vous ne pouvez pas parcourir a #definedans le débogueur, mais vous pouvez parcourir une fonction en ligne.

RichieHindle
la source
8

Les macros ignorent les espaces de noms. Et cela les rend méchants.

Kirill V. Lyadvinsky
la source
3

les fonctions en ligne sont similaires aux macros (car le code de la fonction est développé au moment de l'appel au moment de la compilation), les fonctions en ligne sont analysées par le compilateur, tandis que les macros sont développées par le préprocesseur. En conséquence, il existe plusieurs différences importantes:

  • Les fonctions en ligne suivent tous les protocoles de type sécurité appliqués aux fonctions normales.
  • Les fonctions en ligne sont spécifiées à l'aide de la même syntaxe que toute autre fonction, sauf qu'elles incluent le mot clé en ligne dans la déclaration de fonction.
  • Les expressions passées comme arguments aux fonctions en ligne sont évaluées une fois.
  • Dans certains cas, les expressions passées comme arguments aux macros peuvent être évaluées plusieurs fois. http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx

  • les macros sont développées au moment de la pré-compilation, vous ne pouvez pas les utiliser pour le débogage, mais vous pouvez utiliser des fonctions en ligne.

- bon article : http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1

;

Ahmad
la source
2

Une fonction en ligne conservera la sémantique des valeurs, tandis qu'une macro de préprocesseur ne fait que copier la syntaxe. Vous pouvez obtenir des bogues très subtils avec une macro de préprocesseur si vous utilisez l'argument plusieurs fois - par exemple, si l'argument contient une mutation comme "i ++", avoir cette exécution deux fois est assez surprenant. Une fonction en ligne n'aura pas ce problème.

Michael Donohue
la source
1

Une fonction en ligne se comporte syntaxiquement comme une fonction normale, fournissant une sécurité de type et une portée pour les variables locales de fonction et l'accès aux membres de classe s'il s'agit d'une méthode. De même, lorsque vous appelez des méthodes en ligne, vous devez respecter les restrictions privées / protégées.

heeen
la source
1

Pour connaître la différence entre une macro et une fonction en ligne , nous devons d'abord savoir ce qu'elles sont exactement et quand nous devons les utiliser.

FONCTIONS :

int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
  • Les appels de fonction ont une surcharge qui lui est associée, car après la fin de l'exécution de la fonction, elle doit savoir où elle doit retourner et doit également stocker la valeur dans la mémoire de la pile.

  • Pour les petites applications, ce ne sera pas un problème, mais prenons un exemple d'applications financières où des milliers de transactions se produisent chaque seconde, nous ne pouvons pas utiliser les appels de fonction.

MACROS:

# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
  • Les macros fonctionnent au stade du prétraitement, c'est-à-dire qu'à ce stade, les déclarations écrites avec le mot-clé # seront remplacées par le contenu ie

résultat int = Carré (x * x)

Mais les macros sont associées à des bogues.

#define Square(x) x*x
int main() {
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
    return 0;
}

Ici, la sortie est 11 et non 36 .

FONCTIONS EN LIGNE :

inline int Square(int x) {
    return x * x;
}

int main() {
    using namespace std;
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
    return 0;
}

Sortie 36

Le mot clé en ligne demande au compilateur de remplacer l'appel de fonction par le corps de la fonction, ici la sortie est correcte car elle évalue d'abord l'expression puis transmise.Il réduit la surcharge d'appel de fonction car il n'est pas nécessaire de stocker l'adresse de retour et la pile la mémoire n'est pas requise pour les arguments de fonction.

Comparaison entre les macros et les fonctions en ligne:

  1. Les macros fonctionnent par substitution, tandis que dans les fonctions en ligne, l'appel de fonction est remplacé par le corps.
  2. Les macros sont sujettes aux erreurs en raison de la substitution tandis que les fonctions en ligne sont sûres à utiliser.
  3. Les macros n'ont pas d'adresse alors que les fonctions en ligne ont une adresse.
  4. Les macros sont difficiles à utiliser avec plusieurs lignes de code, contrairement aux fonctions en ligne.
  5. En C ++, les macros ne peuvent pas être utilisées avec les fonctions membres alors que les fonctions en ligne pourraient l'être.

CONCLUSION:

Les fonctions en ligne sont parfois plus utiles que les macros, car elles améliorent les performances et sont sûres à utiliser et réduisent également la surcharge des appels de fonction. C'est juste une demande au compilateur, certaines fonctions ne seront pas intégrées comme:

  • grandes fonctions
  • fonctions ayant trop d'arguments conditionnels
  • code récursif et code avec boucles, etc.

ce qui est une bonne chose, car c'est à chaque fois que le compilateur pense qu'il est préférable de faire les choses d'une autre manière.

Sheetal
la source
Juste une remarque: la macro peut être fixée pour évaluer le même nombre entre crochets. Cependant, il est toujours sujet aux erreurs, car vous devez penser à la substitution stupide absolue et à tous les cas lors de la mise en œuvre.
mike le
0

Dans GCC (je ne suis pas sûr des autres), déclarer une fonction en ligne n'est qu'un indice pour le compilateur. C'est toujours au compilateur à la fin de la journée de décider s'il inclut ou non le corps de la fonction chaque fois qu'elle est appelée.

La différence entre les fonctions en ligne et les macros de préprocesseur est relativement grande. Les macros de préprocesseur ne sont que des remplacements de texte à la fin de la journée. Vous abandonnez une grande partie de la capacité du compilateur d'effectuer la vérification de la vérification de type sur les arguments et le type de retour. L'évaluation des arguments est très différente (si les expressions que vous passez dans les fonctions ont des effets secondaires, vous aurez un temps de débogage très amusant). Il existe des différences subtiles quant à l'utilisation des fonctions et des macros. Par exemple si j'avais:

#define MACRO_FUNC(X) ...

Où MACRO_FUNC définit évidemment le corps de la fonction. Des précautions particulières doivent être prises pour qu'elle fonctionne correctement dans tous les cas où une fonction peut être utilisée, par exemple un MACRO_FUNC mal écrit provoquerait une erreur dans

if(MACRO_FUNC(y)) {
 ...body
}

Une fonction normale pourrait être utilisée sans problème.

Falaina
la source
0

Du point de vue du codage, une fonction en ligne est comme une fonction. Ainsi, les différences entre une fonction en ligne et une macro sont les mêmes que les différences entre une fonction et une macro.

Du point de vue de la compilation, une fonction en ligne est similaire à une macro. Il est injecté directement dans le code, non appelé.

En général, vous devriez considérer les fonctions en ligne comme des fonctions régulières avec quelques optimisations mineures mélangées. Et comme la plupart des optimisations, c'est au compilateur de décider s'il se soucie réellement de l'appliquer. Souvent, le compilateur ignorera volontiers toutes les tentatives du programmeur pour insérer une fonction, pour diverses raisons.

Brian
la source
0

les fonctions en ligne se comporteront comme un appel de fonction s'il existe une instruction itérative ou récursive, de manière à empêcher l'exécution répétée des instructions. Il est très utile de sauvegarder la mémoire globale de votre programme.

Arashdeep singh
la source
-1
#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{ 
    return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases. 
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
 return a*a*a;
}
int main()
{
 cout<<NUMBER<<endl<<number()<<endl;
 cout<<CUBE(1+3); //Unexpected output 10
 cout<<endl<<cube(1+3);// As expected 64
 return 0;
}

Les macros sont généralement plus rapides que les fonctions car elles n'impliquent pas de surcharge réelle des appels de fonction.

Quelques inconvénients des macros: Il n'y a pas de vérification de type. Difficile à déboguer car elles provoquent un simple remplacement. Les macros n'ont pas d'espace de noms, donc une macro dans une section de code peut affecter une autre section. Les macros peuvent provoquer des effets secondaires comme indiqué dans l'exemple CUBE () ci-dessus.

Les macros sont généralement une seule doublure. Cependant, ils peuvent être constitués de plus d'une ligne. Il n'y a pas de telles contraintes dans les fonctions.

rahul_107
la source
À quel point obtenez-vous plus de plaisir #define TWO_N(n) 2 << net ensuite cout << CUBE(TWO_N(3 + 1)) << endl;? (Il est préférable de terminer les lignes de sortie avec endlplutôt que de les commencer avec.)
Jonathan Leffler