0
votes

C ++ Macro ignorant ce qui est après

Je travaillais sur un problème de programmation dynamique et je décidais de ne pas utiliser la fonction STD :: Max, car j'ai pensé qu'une macro serait plus rapide (aucun argument de poussée sur la pile, non modélisé).

mais ça ne marche pas exactement comme prévu. J'ai isolé le problème et on dirait que ceci: xxx

alors qu'il renvoie effectivement le maximum, il semble ignorer l'ajout de 1 après cela. Dans cet exemple, la valeur de C finit par être 0 pendant que je m'attendais à ce que ce soit 1. Pourquoi est-ce?


5 commentaires

Votre expression va étendre à c = (a <= b)? B: A + 1;


ALERTE SPOILER: Les compilateurs ont fait l'inlinage des appels de fonction juste bien pendant des décennies.


Notez que cette macro évaluera deux fois l'un de ses arguments. Pour voir cela, essayez ceci: int f () {std :: cout << "f \ n"; retour 0; } int g () {std :: cout << "g \ n"; retour 1; } maxi (f (), g ()); .


Cette macro produira le résultat "correct" pour maxi (2,1) .


Raison n ° 722 pour ne pas utiliser de macros.


4 Réponses :


3
votes

Votre code après la substitution macro sera la suivante. Voyez-vous maintenant où est l'erreur? XXX PRE>

Pour faire une solution rapide, il suffit de mettre toute votre macro en supplémentaire () comme #define maxi (A, B) (A, B) ((A . C'est une bonne pratique lorsque vous écrivez une macro. Ce changement entraînera la modification suivante du code: P>

// ...
int a = 0, b = 0, c = 0;
c =  ((a <= b)? b : a) + 1;


1 commentaires

Merci! Cela répond ça.



0
votes

Le pré-processeur C ++ remplace les mots avant la compilation Donc, votre ligne devient -

c = ((a<=b) ? b : a) +1;


0 commentaires

0
votes

Je travaillais sur un problème de programmation dynamique et j'ai décidé de ne pas utiliser la fonction STD :: Max, car j'ai pensé qu'une macro serait plus rapide (aucun argument de poussée sur la pile, non modélisé). P>

Votre décision n'est pas très sage. Tout compilateur d'optimisation de moitié décent optimisera l'appel de la fonction dans std :: max code>. Les macros empoisonnent simplement tout ce qu'ils sont impliqués, comme on peut le voir de votre exemple. P>


Pour voir ce qui ne va pas avec votre macro, indiquez à votre compilateur de vous montrer la version prétraitée de votre code source ( -e code> drapeau pour GCC): P>

Ceci: p> xxx pré>

se transforme en ceci: p> xxx pré>

ce qui n'est pas ce que tu voulais. Voici le "Correction": P>

#define maxi(a, b) (((a) <= (b))? (b) : (a))


5 commentaires

Il est moins qu'un compilateur "l'optimise", et plus qu'il ne génère tout simplement pas un appel de fonction inutile en premier lieu. Il interprète ce que le programme décrit par votre code signifie , produit ensuite un programme informatique optimal avec la même signification. Il ne s'agit pas simplement d'aller à la ligne de ligne via votre code la convertissant en une autre langue.


Dans mon expérience, j'ai eu des temps visiblement différents avec des fonctions / macros inlinées que des fonctions régulières sur les sites de codage, donc ils n'étaient peut-être pas optimistes exprès.


Je ne sais pas ce que sont ces "sites codants", mais s'ils utilisent -O0 (a "entrent dans un mode où nous faire juste la ligne-ligne Convertissez votre code pour que vous puissiez déboguer plus facilement «la fonctionnalité), alors ils ne testent rien vraiment réel.


@Asteroidswithwings qui est très correct. Le point clé est que le compilateur ne génère pas votre programme dans une langue différente. Il génère un programme similaire qui a le même comportement observable.


Tache sur :) pourrait ressembler à de la nitpicking, ou une distinction académique, mais je crois vraiment que la compréhension est essentielle pour comprendre pourquoi, par exemple, les programmes d'écriture avec un comportement non défini sont une mauvaise idée, même si vous pensez "c'est juste une mémoire emplacement".



1
votes

Votre macro manque à plusieurs parenthèses pour éviter de se briser dans certaines expressions, par ex. Dans votre cas montré, il sera remplacé par: xxx

et comme vous pouvez le constater, vous reviendrez soit B ou A + 1 . Ce n'est pas ce que vous vouliez.

Vous devez écrire la macro comme xxx

pour éviter des problèmes aussi similaires dans les arguments.

Ceci n'est en aucun cas plus efficace que std :: max . Les compilateurs font de petites fonctions en ligne et après l'inlinage, la fonction utilisant std :: max sera à peu près la même que si maxi était substitué. Il n'y aura pas de passage d'arguments de fonction, que ce soit dans des registres ou sur la pile.

BTW. Une fonction étant modélisée ou non n'a aucun impact sur ses caractéristiques de performance. Donc, je ne sais pas pourquoi vous mentionnez cela dans la question.

Et comme vous pouvez le constater que les macros sont beaucoup plus difficiles à travailler, il n'y a donc aucune raison de les utiliser.

Au contraire, votre macro sera pire dans certaines situations, par exemple: xxx

f est une fonction, substituera à (à peu près) xxx

signifiant que f sera toujours évalué trois heures, pour les deux premiers appels Dans la comparaison et une fois pour la branche choisie.

d'autre part std :: max (f (a), f (b)) évalue f seulement deux fois .

Cela signifie que la macro prendra non seulement plus de temps, il aura également des effets inattendus si les appels de fonction ont des effets secondaires. < / p>


0 commentaires