2010-08-24 21 views
8

Comme le titre le dit; Quelle est la différence entre le mot clé inline et la directive du préprocesseur #define?Quelle est la différence dans la pratique entre inline et #define?

+0

double possible [Les fonctions inline vs préprocesseur macros] (http (Eh bien, je reconnais que faire avec abs est un peu artificielle, mais j'espère que vous obtenez l'image.): // stackoverflow.com/questions/1137575/inline-functions-vs-preprocessor-macros) – jww

Répondre

37

#define est un outil de préprocesseur et possède une macro sémantique. Considérez ceci, si max(a,b) est une macro définie comme

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

Ex 1:

val = max(100, GetBloodSample(BS_LDL)) déborderaient le sang innocent supplémentaire, parce que la fonction sera effectivement appelé deux fois. Cela pourrait signifier une différence de performance significative pour des applications réelles.

Ex 2:

val = max(3, schroedingerCat.GetNumPaws()) Cela démontre une sérieuse différence dans la logique du programme, car cela peut revenir de façon inattendue un nombre qui est inférieur à 3 - quelque chose que l'utilisateur ne s'attendre.

Ex 3:

val = max(x, y++) pourrait augmenter y plus d'une fois.


Avec fonctions en ligne, aucun d'entre eux se produira.

La raison principale est que le concept macro cible la transparence de l'implémentation (remplacement du code textuel) et inline cible les concepts de langage appropriés, rendant la sémantique d'invocation plus transparente pour l'utilisateur.

+3

+1 Pour l'exemple de déversement de sang – Tomas

+2

Vous devez remplacer 'shroedingerCat.GetNumPaws()' par une fonction C, pas C++. – alternative

+0

Eh bien, la question concerne C; Il est cependant plus fréquent que les fonctions membres du C++ retournent des choses différentes de temps en temps, car elles dépendent naturellement de l'état de leur objet. –

1

macros (créées avec #define) sont toujours remplacés par écrit et peuvent avoir des problèmes à double évaluation. D'autre part, est purement consultatif - le compilateur est libre de l'ignorer. Sous la norme C99, une fonction inline peut également avoir un lien externe, créant une définition de fonction qui peut être liée.

1

Eh bien, une ligne multi-lignes #define est plus difficile à écrire et à éditer qu'une fonction en ligne. Vous pouvez définir une fonction en ligne comme n'importe quelle fonction normale et définir des variables sans problèmes. Imaginez que vous vouliez appeler un bloc de code plusieurs fois dans une autre fonction, et que ce bloc de code nécessite ses propres variables: c'est plus facile avec les fonctions inline (oui, vous pouvez le faire aveC#defines et do { ... } while (0); mais c'est quelque chose que vous devez Penser à). De plus, avec le débogage activé, vous obtenez normalement un cadre de pile "simulé" pour les fonctions inline qui peut parfois faciliter le débogage (du moins c'est ce que vous obtenez lorsque vous compilez/connectez avec -g de gcc et déboguez avec GDB, IIRC). Vous pouvez placer des points d'arrêt dans votre fonction inline. En dehors de cela, le résultat devrait être presque identique, AFAIK.

0

Les macros de type fonction vous permettent d'effectuer un contrôle de cohérence absolu à l'endroit où elles sont définies.Lorsque vous utilisez une macro, tout va bien fonctionner à un endroit et être brisé ailleurs, et vous ne saurez pas pourquoi jusqu'à ce que vous ayez perdu plusieurs heures de travail ou de sommeil. Les macros fonctionnelles ne fonctionnent pas sur les données, elles fonctionnent sur le code source. Parfois c'est bon, par exemple quand vous voulez des instructions de débogage réutilisables qui utilisent FILE et LINE intégrées, mais la plupart du temps, cela peut être fait aussi bien avec une fonction inline, qui est vérifiée pour la syntaxe au point de définition comme toute autre fonction.

2

Les fonctions (que ce soit inline ou non) et les macros remplissent différentes fonctions. Leur différence ne devrait pas être considérée comme idéologique comme certains semblent le prendre, et ce qui est encore plus important, ils peuvent bien fonctionner ensemble.

Les macros sont le remplacement du texte qui se fait au moment de la compilation et ils peuvent faire des choses comme

#define P99_ISSIGNED(T) ((T)-1 < (T)0) 

qui vous donne une expression de compilation ou non un type intégral est signé ou non. Autrement dit, ils sont idéalement utilisés lorsque le type d'une expression n'est pas connu (à la définition) et que vous voulez faire quelque chose à ce sujet. D'autre part, le piège avec les macros est que leurs arguments peuvent être évalués plusieurs fois, ce qui est mauvais en raison des effets secondaires. D'autre part, les fonctions (inline) sont dactylographiées, ce qui les rend plus strictes ou, en termes négatifs, moins flexibles. Tenir compte des fonctions

inline uintmax_t absU(uintmax_t a) { return a; } 
inline uintmax_t absS(uintmax_t a) { 
    return (-a < a) ? -a : a; 
} 

La première met en œuvre la fonction abs trivial pour un type intégral non signé. La seconde l'implémente pour un type signé. (oui, il faut un argument non signé, c'est pour but.)

Nous pouvons les utiliser avec n'importe quel type intégral. Mais, le type de retour sera toujours de la plus grande largeur et il y a une certaine difficulté à savoir comment choisir entre les deux.

Maintenant, avec la macro suivante

#define ABS(T, A) ((T)(P99_ISSIGNED(T) ? absS : absU)(A)) 

nous avons mis en place un

  • famille de fonctions
  • qui fonctionne pour tout type intégral
  • qui évalue son argument une seule fois
  • pour lequel tout compilateur récent et décent créera code optimal