Quel est le pire abus de macros / pré-processeur dans le monde réel que vous ayez jamais rencontré (s'il vous plaît pas de réponses artificielles IOCCC * haha *)?
Veuillez ajouter un court extrait ou une histoire si elle est vraiment divertissante. Le but est d'enseigner quelque chose au lieu de toujours dire aux gens "ne jamais utiliser de macros".
ps: J'ai déjà utilisé des macros ... mais d'habitude je m'en débarrasse finalement quand j'ai une "vraie" solution (même si la vraie solution est en ligne donc elle devient similaire à une macro).
Bonus: donnez un exemple où la macro était vraiment meilleure qu'une solution non macro.
Question connexe: Quand les macros C ++ sont-elles utiles?
c++
c
macros
preprocessor
Trevor Boyd Smith
la source
la source
Réponses:
De mémoire, cela ressemblait à ceci:
Oui c'est vrai, pas d'accolades fermantes dans aucune des fonctions. La coloration syntaxique était un gâchis, donc il a utilisé vi pour éditer (pas vim, il a une coloration syntaxique!)
C'était un programmeur russe qui avait principalement travaillé en langage d'assemblage. Il était fanatique de sauvegarder autant d'octets que possible car il avait auparavant travaillé sur des systèmes avec une mémoire très limitée. "C'était pour le satellite. Seulement très peu d'octets, donc nous utilisons chaque octet pour beaucoup de choses." (peu de tripotage, réutilisation des octets d'instructions de la machine pour leurs valeurs numériques) Quand j'ai essayé de découvrir quels types de satellites, je n'ai pu obtenir que "Satellite en orbite. Pour mettre en orbite."
Il avait deux autres bizarreries: un miroir convexe monté au-dessus de son moniteur "Pour savoir qui regarde", et une sortie soudaine occasionnelle de sa chaise pour faire dix pompes rapides. Il a expliqué ce dernier comme "le compilateur a trouvé une erreur dans le code. C'est une punition".
la source
Mon pire:
J'ai passé deux jours de ma vie à traquer un problème de comptage de références COM multi-thread parce qu'un idiot l'a mis dans un fichier d'en-tête. Je ne mentionnerai pas l'entreprise pour laquelle je travaillais à l'époque.
La morale de cette histoire? Si vous ne comprenez pas quelque chose, lisez la documentation et apprenez-en davantage. Ne faites pas que disparaître.
la source
la source
for (;;)
idiome, sinon j'ajouterais immédiatement cette macro à mon code.(defmacro ever ())
et ensuite(require 'cl (ever))
Défi: Quelqu'un peut-il le faire avec moins de définitions et de structures? ;-)
la source
public
etstatic as nothing,
vide` commeint
, etmain(x)
commemain()
,public static void main(String[] args)
se transforme enint main()
. Puis seSystem
transforme enS s;s
, donc seSystem.out.println("Hello World!");
transforme enS s; s.out.println("Hello World!");
qui appelle laprintln
fonction dans laF
structure dans laS
structure.la source
class
mot - clé et le premier modificateur d'accès.#define class struct #define protected public
C'était une blague jouée sur quelqu'un, ça n'a pas été trouvé amusant par les personnes affectées
la source
Le hideux:
Sérieusement, si vous voulez coder en Pascal, achetez un compilateur Pascal, ne détruisez pas le beau langage C.
la source
Un `` architecte '', un gars très humble, vous connaissez le type, avait ce qui suit:
parce qu'il aimait taper vite. Le chirurgien du cerveau aimait crier sur des gens qui étaient plus intelligents que lui (ce qui était à peu près tout le monde), et menaçait d'utiliser sa ceinture noire sur eux.
la source
killall rn
?Monde réel? MSVC a des macros dans minmax.h, appelées
max
etmin
, qui provoquent une erreur du compilateur chaque fois que j'ai l'intention d'utiliser lastd::numeric_limits<T>::max()
fonction standard .la source
Un mélange entre la syntaxe Pascal et les mots-clés français:
la source
Raymond Chen a une très bonne diatribe contre l'utilisation de macros de contrôle de flux . Son meilleur exemple vient directement du code source original du Bourne Shell:
la source
if
...else
...elif
...fi
etcase
...esac
avant (dans le langage même que Bourne a inventé pour sh), maisloop
...pool
c'est un vrai bijou.Je voudrais soumettre pour le concours une gemme appelée chaos-pp , qui implémente un langage fonctionnel au moyen des macros du préprocesseur.
Un des exemples est le calcul du 500ème nombre de fibonacci entièrement par le préprocesseur:
Le code d'origine avant le préprocesseur ressemble à ceci:
en prétraitant le fichier, nous obtenons le résultat suivant (après une attente assez longue):
la source
Directement depuis Qt:
Vraiment agréable d'interagir avec d'autres bibliothèques comme boost :: signaux ... Juste un exemple, il y en a beaucoup d'autres dans Qt qui créent du code amusant comme:
Et c'est C ++ ... mais du coup:
N'est plus C ++ valide.
la source
Windows.h a beaucoup de fonctions qui ont abusé des macros.
MrValdez est agacé par la macro GetObject trouvée dans Windows.h
La macro GetObject change la fonction GetObject () en GetObjectA () ou GetObjectW () (selon si la construction est compilée en non-unicode et unicode, respectivement)
MrValdez déteste avoir à faire avant la ligne de fonction GetObject
L'alternative est de changer le nom de la fonction en quelque chose d'autre comme GetGameObject ()
jdkoftinoff dans les commentaires l'ont cloué: le problème est que toutes les fonctions de l'API Windows sont des macros.
Adam Rosenfield a mentionné que les problèmes peuvent être résolus en définissant NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX, etc. avant d'inclure windows.h pour supprimer les problèmes.
la source
c'est tellement mauvais. Il est aléatoire, ce qui signifie qu'il se déclenche à différents endroits tout le temps, qu'il change l'instruction de retour, qui contient généralement du code qui pourrait échouer tout seul, qu'il change un mot-clé innocent dont vous ne serez jamais suspect et qu'il utilise exception de l'espace std afin que vous n'essayiez pas de rechercher dans vos sources pour trouver sa source. Tout simplement génial.
la source
Un collègue et moi avons trouvé ces deux joyaux dans certains de nos codes pour le streaming d'objets. Ces macros ont été instanciées dans CHAQUE SINGLE fichier de classe qui effectuait le streaming. Non seulement ce code hideux est répandu partout dans notre base de code, mais lorsque nous avons approché l'auteur original à ce sujet, il a écrit un article de 7 pages sur notre wiki interne en défendant cela comme le seul moyen possible d'accomplir ce qu'il essayait de faire ici.
Inutile de dire qu'il a depuis été remanié et n'est plus utilisé dans notre base de code.
Ne vous laissez pas impressionner par les mots-clés mis en évidence. C'est TOUT une macro
Mise à jour (17 décembre 2009):
Encore de bonnes nouvelles concernant cet horrible auteur de macro. En août, l'employé responsable de cette monstruosité a été limogé.
la source
J'ai fait ce qui suit moi-même et je pense que j'en ai appris quelque chose.
En 1992 environ, j'ai écrit un petit interprète Lisp. Il n'a pas été implémenté en C normal, mais dans un langage interprété de type C. Ce langage de type C utilisait cependant le préprocesseur C standard.
L'interpréteur Lisp contenait bien sûr les fonctions car , qui est utilisée en Lisp pour renvoyer le premier élément d'une liste, et cdr , qui renvoie le reste de la liste. Ils ont été mis en œuvre comme ceci:
(Les données ont été stockées dans des tableaux, car il n'y avait pas de structure. CONS_OFFSET est la constante 1000.)
car et cdr sont fréquemment utilisés en Lisp et sont courts, et comme les appels de fonction n'étaient pas très rapides dans le langage d'implémentation, j'ai optimisé mon code en implémentant ces deux fonctions Lisp sous forme de macros:
CHECK_CONS vérifie que son argument est en fait une liste, et comme celui-ci est également utilisé fréquemment dans l'interpréteur, et est court, j'ai également écrit celui-là sous forme de macro:
IS_CONS et LISP_ERROR ont également été utilisés fréquemment, donc je les ai également transformés en macros:
Cela semble raisonnable?
Mais alors, pourquoi tout le système s'est-il écrasé sur cette ligne:
J'ai travaillé longtemps pour trouver le problème, jusqu'à ce que je vérifie enfin à quoi cette ligne courte a été étendue par le pré-processeur. Il a été étendu à une ligne de 31370 caractères, que j'ai ici divisée en lignes (502 d'entre elles) pour plus de clarté:
la source
I optimized my code by implementing those [..] functions as macros
- derniers mots célèbres ...Une fois, j'ai dû porter une application C d'Unix vers Windows, dont la nature spécifique restera sans nom pour protéger les coupables. Le type qui l'a écrit était un professeur peu habitué à écrire du code de production et qui était clairement venu en C depuis un autre langage. Il arrive aussi que l'anglais ne soit pas sa langue maternelle, bien que le pays dont il est originaire la majorité des gens le parle assez bien.
Son application a fait un usage intensif du préprocesseur pour tordre le langage C dans un format qu'il pourrait mieux comprendre. Mais les macros qu'il a le plus utilisées ont été définies dans un fichier d'en-tête nommé 'Thing.h' (sérieusement), qui comprenait les éléments suivants:
... qu'il a ensuite utilisé pour écrire des monstruosités telles que:
L'ensemble du projet (~ 60 000 LOC) a été écrit dans un style similaire - marco hell, noms étranges, jargon Olde-anglais, etc. Heureusement, nous avons pu jeter le code car j'ai trouvé une bibliothèque OSS qui exécutait le même algorithme des dizaines des fois plus vite.
(J'ai copié et édité cette réponse que j'ai faite à l'origine sur cette question ).
la source
Le pire que j'aie jamais rencontré était dans un produit contenant une suite d'exécutables où le responsable technique désigné n'avait pas compris les bibliothèques.
Au lieu de cela, il avait des ensembles de fichiers partagés dans plusieurs dossiers Visual Source Safe. Il s'est alors rendu compte qu'ils devaient se comporter légèrement différemment pour chaque application.
Vous pouvez appliquer un certain nombre d'étapes de refactoring ici.
Au lieu de cela, il a utilisé #ifdefs
la source
L'utilisation du préprocesseur LINE pour générer un ID unique pour les messages passés sur le réseau:
Voici un exemple où la macro était vraiment meilleure qu'une solution non macro:
Dans une solution non macro, les classes, les fonctions et les variables doivent être construites pour garder une trace de l'ID du message. Le développeur peut compliquer ou non le suivi de l'ID de message, alors que cela est plus facile à lire et à déboguer.
De plus, il est plus facile d'ajouter de nouveaux messages simplement en ajoutant le message dans la source.
L'inconvénient de cette situation est que le fichier doit être inclus dans tout code utilisant des messages. Le temps de compilation augmenterait chaque fois qu'un message est édité.
la source
Un assez mauvais exemple:
Cela permet à une structure C qui contient une variable membre appelée
class
d'être gérée par un compilateur C ++. Il y a deux en-têtes avec cette construction dedans; l'un d'eux contient également '#undef class' à la fin et l'autre pas.la source
@class
place declass
.Dans un an du concours international de codage C obscurci, il y avait une entrée où tout le programme était:
P
À condition que vous puissiez définir
P
dans le makefile le programme de votre choix.Si je me souviens bien, il a gagné dans l'une des catégories, et l'année suivante, une règle est apparue interdisant ce style d'entrée.
(Edit: six mois plus tard ou quelque chose du genre ... Je suis sûr que le "No IOCCC" n'était pas dans la question principale quand j'ai écrit ceci ...)
la source
Je m'ennuyais un jour et je jouais avec des blocs en Objective-C ...
autorisant des choses "intéressantes" comme:
(certaines définitions de fonctions et de classes ne sont pas affichées par souci de concision)
la source
Le pire que j'ai vu était la non-utilisation :-)
Quelqu'un a écrit une fonction strcpy (je pense que c'était ça ... il y a plus de 10 ans maintenant) à l'intérieur d'une méthode (parce qu'ils ne voulaient pas la surcharge d'appeler strcpy ... soupir).
Ils ont compris que cela ne fonctionnerait pas pour les caractères japonais, ils ont donc ajouté un "si" au début pour faire ASCII ou Unicode. À ce moment-là, le code durait environ un écran ... tuant probablement la cohérence du cache et effaçant ses économies supposées pour l'inlining du code.
Le code était identique sauf pour les types (donc aurait dû utiliser une macro).
Bien sûr, le strcpy qu'ils ont écrit était beaucoup plus lent que celui de l'assembleur réglé à la main qui se trouvait dans la bibliothèque standard ...
Bien sûr, s'ils venaient de tout faire sous forme de macro, cela aurait pu être remplacé par un appel à strcpy ...
Bien sûr, j'ai quitté l'entreprise (pas directement à cause de cela ...)
la source
The code was identical save for the types (so should have used a macro).
Non, il aurait dû utiliser un modèle.L'obligatoire
et
Qui savait?
la source
La personne qui a fait cela s'est expliqué quelques années plus tard - la plupart (sinon la totalité) des fonctions de la bibliothèque C renvoient 0 pour indiquer que tout s'est bien passé. Donc, il voulait être capable d'écrire du code comme:
Inutile de dire que personne dans notre équipe (testeur ou développeur) n'a jamais osé revoir son code.
la source
#define FLAG_SUCCESS 0
?Je maintiens du code qui a des gotos dans les macros. Ainsi, une fonction aura une étiquette à la fin mais aucun goto visible dans le code de fonction. Pour aggraver les choses, la macro se trouve à la fin des autres instructions, généralement hors de l'écran, sauf si vous faites défiler horizontalement.
la source
goto
instructions et les définitions des étiquettes cibles. Totalement magique.la source
Par un camarade de classe qui n'a pas compris les règles sur les nombres magiques:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1
la source
ASA - http://www.ingber.com/#ASA
Il faut vraiment le télécharger pour l'apprécier. L'ensemble du flux de travail est déterminé par des macros. C'est complètement illisible. Par exemple -
etc.
Et ce n'est que la configuration des options. tout le programme est comme ça.
la source