Quel est le pire abus de macros / pré-processeur dans le monde réel que vous ayez jamais rencontré?

176

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?

Trevor Boyd Smith
la source
+1 pour avoir attiré l'attention sur les abus généralisés que j'ai subis aux mains des macros.
i_am_jorf
37
#define true false // débogage heureux :)
n0rd
Le wiki de la communauté signifie que personne ne gagnera (ou ne perdra) de réputation en votant à la hausse ou à la baisse sur cette question ou ses réponses. Beaucoup de gens considèrent des questions comme celle-ci comme des moyens peu coûteux et faciles de gagner en réputation, donc si vous le marquez comme wiki communautaire, les gens sont moins susceptibles de se déformer et de le fermer.
Graeme Perrow
2
«les gens risquent de se déformer et de le fermer»: insinuez-vous que vous ne voulez pas de contenu humoristique / drôle sur le débordement de pile?
Trevor Boyd Smith
2
Juste un petit point, le pré-processeur fait partie du langage et donc pas mal / mal à utiliser, comme toute autre chose.
M. Boy

Réponses:

410

De mémoire, cela ressemblait à ceci:

#define RETURN(result) return (result);}

int myfunction1(args) {
    int x = 0;
    // do something
    RETURN(x)

int myfunction2(args) {
    int y = 0;
    // do something
    RETURN(y)

int myfunction3(args) {
    int z = 0;
    // do something
    RETURN(z)

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".

user78859
la source
87
"Le compilateur a trouvé une erreur dans le code. C'est une punition". !! La société vous a trouvé ... punition pour les collègues!
Apprentissage du
227
En Russie soviétique, le programme VOUS compile!
Crashworks
53
Quand j'ai lu l'erreur du compilateur "punition", la première chose à laquelle j'ai pensé était "Dobby devait repasser ses mains".
Graeme Perrow
124
Je pense que les programmeurs (moi-même inclus) seraient beaucoup plus en forme si nous faisions tous 10 pompes à chaque fois qu'un compilateur trouvait une erreur dans notre code. Cela peut également réduire la fréquence des tests par compilation.
MikeyB
5
Ce mec a l'air génial. Mais oui, je ne vois pas comment cela est censé améliorer la taille du code.
jalf
274

Mon pire:

#define InterlockedIncrement(x) (x)++
#define InterlockedDecrement(x) (x)--

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.

i_am_jorf
la source
146
@Joshua: Si vous exécutez ce code dans un environnement multithread, vous pourriez le faire involontairement
1800 INFORMATIONS
11
"Si vous ne comprenez pas quelque chose, lisez la documentation et renseignez-vous. Ne faites pas que disparaître." - AMEN!
Paul Alexander
2
@ 1800 Information: je pense que vous perdriez juste des votes, c'est pourquoi je ne peux pas vous en donner un; p
wkf
5
Pardonnez-moi en tant que programmeur non-C ++: le problème principal ici est-il qu'une fonction threadsafe est convertie en une fonction non threadsafe? Ou qu'InterlockedIncrement attend un pointeur, alors vous allez maintenant augmenter le pointeur au lieu de ce sur quoi il pointe? Ou les deux?
Tim Pietzcker
38
Le problème est qu'InterlockedIncrement est normalement une fonction atomique définie dans l'API Windows. Ainsi, lorsque les gens appellent InterlockedIncrement, ils s'attendent à appeler une fonction dont l'exécution est garantie de manière atomique. Au lieu de cela, quelqu'un a défini une macro avec le même nom, qui s'évalue en un incrément simple et non atomique
jalf
166
#define ever (;;)
for ever { 
   ...
}
Joël Spolsky
la source
52
Je préfère <#define forever for (;;)> afin que vous puissiez écrire <forever {...}>
paxdiablo
quelqu'un que je suis allé à l'école avec des notes perdues pour la chose EVER ... il était étouffé comme dans le manuel :-)
TofuBeer
6
La suggestion de Pax n'est-elle pas directement de K&R? Pourtant, cela ne vaut pas la peine, je dirais.
Jon Ericson
Ce n'est en fait pas mal du tout. Je n'utilise pas d' for (;;)idiome, sinon j'ajouterais immédiatement cette macro à mon code.
Du
1
@hayalci: Dans emacs lisp (et certaines implémentations courantes de lisp), vous pouvez le faire (defmacro ever ())et ensuite(require 'cl (ever))
Joe D
145
#include <iostream>
#define System S s;s
#define public
#define static
#define void int
#define main(x) main()
struct F{void println(char* s){std::cout << s << std::endl;}};
struct S{F out;};

public static void main(String[] args) {
  System.out.println("Hello World!");
}

Défi: Quelqu'un peut-il le faire avec moins de définitions et de structures? ;-)

Franc
la source
19
vous venez d'écrire un convertisseur java-vers-c! horray!
Andreas Petersson
25
Signalé comme "offensant". (I kid!)
Annika Backstrom
40
C'est soit affreusement beau ou magnifiquement hideux.
Chris Lutz
38
@Mark - Il déclare publicet static as nothing, vide` comme int, et main(x)comme main(), public static void main(String[] args)se transforme en int main(). Puis se Systemtransforme en S s;s, donc se System.out.println("Hello World!");transforme en S s; s.out.println("Hello World!");qui appelle la printlnfonction dans la Fstructure dans la Sstructure.
Chris Lutz
2
Jetez un œil à ceci: mailcom.com/ioccc/chia/chia.c (téléchargez-le et compilez-le)
Roberto Bonvallet
130
#define private public
Andy White
la source
J'ai déjà fait ça. Parfois, vous avez juste besoin de modifier une variable membre ou de remplacer une fonction dans un code tiers que vous ne pouvez pas modifier - et ils ne vous ont pas fourni d'accesseur.
Michael Kristofik
30
wow pour les tests unitaires, cela pourrait même être utile, même si les fantômes de la conception d'objets vous hanteront la nuit.
Epaga
12
Hmmm, comportement indéfini, violation facile de la règle à une définition, différences de mise en page potentielles. Ouais, c'est un gagnant.
David Thornley
10
Donc, avec cela, je peux accéder à des éléments privés et publics, mais pas à des éléments protégés, et je ne peux pas accéder aux éléments entre le classmot - clé et le premier modificateur d'accès.
Ken Bloom
3
@Ken:#define class struct #define protected public
Yakov Galka
107
#define if while

C'était une blague jouée sur quelqu'un, ça n'a pas été trouvé amusant par les personnes affectées

Michael McCarty
la source
22
#define while if serait encore plus insidieux.
starblue
7
Nous devrions clarifier votre déclaration. Cela n'a pas été trouvé amusant par les personnes touchées . :-)
Andrew Shepherd
6
Quand je faisais des devoirs, je faisais souvent ce genre de choses exprès, juste pour ennuyer mes professeurs.
pyon
15
C'est une bonne farce mais elle ne sera pas compilée s'il y a des déclarations "else". J'ai trouvé que #define if (x) if (true) est le plus efficace.
Graphics Noob
32
J'ai toujours préféré #define sizeof (x) rand ()
Jon
106

Le hideux:

#define begin {
#define end }
/* and so on */

Sérieusement, si vous voulez coder en Pascal, achetez un compilateur Pascal, ne détruisez pas le beau langage C.

paxdiablo
la source
45
Maintenant, vous me demandez quelles langues je peux simuler avec un fichier d'en-tête assez intelligent.
Bill the Lizard
47
C n'est pas beau. C'est plutôt moche.
rlbond
27
Sa beauté réside dans sa simplicité. On dit qu'il a toute la vitesse du langage d'assemblage combinée à la lisibilité du ... langage d'assemblage :-) Je le préfère au C ++ gonflé (bien que je préfère Java dans mon travail quotidien en raison de son énorme bibliothèque).
paxdiablo
9
Pas vraiment. Trouvez la source originale de Bourne pour la coque bourne. Il a fait exactement cela pour obtenir une sorte de gâchis bâtard de type ALGOL.
RBerteig
3
#define DO for (int _i = 0; _i <= 1; ++ _ i) {if (_i == 1) //// LINE BREAK //// #define IF (cond); if (! (cond)) break; } //// SORTIE DE LIGNE //// DO printf ("a") IF (1 == 2);
Adrian Panasiuk
93

Un `` architecte '', un gars très humble, vous connaissez le type, avait ce qui suit:

#define retrun return

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.

dcw
la source
Je fais tellement cette faute de frappe que je l'ai vraiment considérée.
Joshua
4
apprenez plutôt à votre éditeur à remplacer automatiquement le retour en retour. J'ai fait de tels hackeries à mon client IRC, au moins
Tetha
1
Hé, je pense que je travaillais aussi avec cet «architecte». Il a finalement été reclassé en tant qu'architecte principal lorsqu'il avait besoin d'apaiser son ego.
BIBD
1
J'avais redéfini «rn» en «rm» dans bash, parce que je ne pouvais pas taper et que le lecteur de nouvelles «rn» mettait 5 minutes à démarrer et à se connecter au serveur.
Martin Beckett
2
Vous ne pouvez pas simplement ouvrir un nouveau terminal (ou passer à un autre vt) et faire killall rn?
Joe D
69

Monde réel? MSVC a des macros dans minmax.h, appelées maxet min, qui provoquent une erreur du compilateur chaque fois que j'ai l'intention d'utiliser la std::numeric_limits<T>::max()fonction standard .

xtofl
la source
2
Ah, oui, c'est pourquoi j'avais un en-tête spécial avec des # undef pour restaurer la santé mentale après ceux spécifiques à MS ...
Pontus Gagge
3
Résolu avec (std :: numeric_limits <T> :: max) () Mais oui, assez ennuyeux.
rlbond
36
Ajoutez NOMINMAX aux propriétés de votre projet sous C / C ++ -> Préprocesseur -> Définitions de préprocesseur.
mattnewport
18
Ces macros ont existé dans les en-têtes MS plus longtemps que min et max ont été dans la bibliothèque standard C ++.
Richard
4
C'est encore pire lorsque quatre de vos autres dépendances externes définissent également leur propre min / max, avec des degrés divers de suckiness, allant de macros mal entre parenthèses à des modèles bien écrits, et l'un d'entre eux doit simplement rendre impossible l'indéfini ou sinon sauter ces ... Dans mon livre, la langue est à 50% à blâmer.
Roman Starkov
58

Un mélange entre la syntaxe Pascal et les mots-clés français:

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }
mouviciel
la source
36
#define zut_alors exit (-1)
MikeyB
4
C'est génial et ça m'a fait rire aux éclats. Donc, il s'agit essentiellement d'une version française localisée de Basic implémentée en C?
Bobby
56

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:

ADDRESS alloc(nbytes)
    POS     nbytes;
{
    REG POS rbytes = round(nbytes+BYTESPERWORD,BYTESPERWORD);

    LOOP    INT     c=0;
    REG BLKPTR  p = blokp;
    REG BLKPTR  q;
    REP IF !busy(p)
        THEN    WHILE !busy(q = p->word) DO p->word = q->word OD
        IF ADR(q)-ADR(p) >= rbytes
        THEN    blokp = BLK(ADR(p)+rbytes);
            IF q > blokp
            THEN    blokp->word = p->word;
            FI
            p->word=BLK(Rcheat(blokp)|BUSY);
            return(ADR(p+1));
        FI
        FI
        q = p; p = BLK(Rcheat(p->word)&~BUSY);
    PER p>q ORF (c++)==0 DONE
    addblok(rbytes);
    POOL
}
1800 INFORMATIONS
la source
2
Deux points: premièrement, cette pâte a gâché l'indentation d'origine. Et deuxièmement, le code a l'air bien pour ce qu'il est: Unix C des années 1970 par un fervent fan d'Algol-68. Si _pourquoi le raide chanceux peut s'exprimer dans un style décalé, pourquoi Steve Bourne ne le peut-il pas? Bien sûr, quelqu'un condamné à le maintenir qui ne connaît pas Algol 68 n'appréciera peut-être pas cette chance d'élargir ses propres goûts.
Darius Bacon
Je pense que cela pourrait être considéré comme une blague par Steve Bourne plutôt qu'un style de programmation suggéré
Martin Beckett
2
J'ai vu if... else... elif... fiet case... esacavant (dans le langage même que Bourne a inventé pour sh), mais loop... poolc'est un vrai bijou.
hobbs
54

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:

int main(void) {
   printf
     ("The 500th Fibonacci number is "
      ORDER_PP(8stringize(8to_lit(8fib(8nat(5,0,0)))))
      ".\n");
   return 0;
}

en prétraitant le fichier, nous obtenons le résultat suivant (après une attente assez longue):

$ cpp -I../inc fibonacci.c 2>/dev/null | tail
  return fib_iter(n, 0, 1);
}
# 63 "fibonacci.c"
int main(void) {
   printf
     ("The 500th Fibonacci number is "
      "139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125"
      ".\n");
   return 0;
}
Andrew Y
la source
1
Vous pouvez récupérer le code de CVS et y jeter un œil. J'avais mis plus de détails à ce sujet dans mon blog il y a quelque temps quand je suis tombé dessus: bnpcs.blogspot.com/2009/02/ ... Sinon pour le problème de débogage du code résultant (le problème d'avoir des lignes extrêmement longues si ils sont générés par un tel "langage"), il aurait même pu être utilisable comme générateur de code pratique pour C.
Andrew Y
Je peux juste imaginer que la compilation prend une éternité
Paul Fultz II
52

Directement depuis Qt:

#define slots   /* */
#define signals /* */

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:

class X : public QObject {
   Q_OBJECT
private slots:
   //...
public signals:
   //...
};

Et c'est C ++ ... mais du coup:

boost::signals::trackable

N'est plus C ++ valide.

David Rodríguez - Dribeas
la source
5
:) Donc c'est une macro qui casse les autres bibliothèques pour rien. C'est encore mieux que ce à
quoi
38
Qt est très territorial et attaquera vicieusement d'autres bibliothèques qui tenteront d'occuper son espace de noms :)
Jeremy Friesner
21
Malheureusement, Qt attaque des bibliothèques en dehors de son espace de noms avec l'utilisation de macros
David Rodríguez - Dribeas
7
Heureusement, boost :: signaux2 a résolu ce problème;)
bdonlan
9
Utilisez Q_SIGNALS et Q_SLOTS si vous avez peur de cette interaction.
Tadeusz A. Kadłubowski
50

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

#undef GetObject

Object *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.

MrValdez
la source
3
Vous pouvez supprimer cela, mais # en définissant NOGDI avant d'inclure windows.h, à condition bien sûr que vous n'ayez pas besoin d'utiliser l'une des différentes fonctions GDI. Il existe un tas d'autres macros telles que WIN32_LEAN_AND_MEAN, NOMINMAX, etc. qui empêchent la définition ou l'inclusion d'autres éléments.
Adam Rosenfield
1
GetObject est un nom de fonction assez générique. Peut-être auriez-vous pu utiliser un nom plus descriptif étant donné le contexte pour éviter la collision. Cependant, c'est un cas macro assez mauvais.
strager
1
Il est assez ennuyeux que win32 ait toutes les macros pour convertir les noms d'API en FooA et FooW. Nous avons un problème avec SendMessage.
i_am_jorf
6
Le problème est que toutes les fonctions de l'API Windows sont des macros. Celui qui m'a mordu était GetTickCount (). Comme je fais la plupart de ma programmation en dehors de Windows, j'ai trouvé toutes les définitions dans les en-têtes de Windows, puis j'ai créé mon propre fichier d'inclusion qui les définissait tous pour vérifier la compatibilité au préalable.
jdkoftinoff
12
Je pense que nous avons un gagnant. C'est du monde réel, c'est une idée ridiculement mauvaise, et cela a affecté un grand nombre de programmeurs innocents. Quiconque est responsable de ce bijou chez Microsoft devrait être considéré comme un criminel de guerre ... La meilleure partie est que Microsoft n'a pas hésité à utiliser des noms aussi étonnamment courants, comme GetObject, SendMessage ou CreateWindow.
jalf
45
#define return if (std::random(1000) < 2) throw std::exception(); else return

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.

vava
la source
4
Je viens de tester celui-ci, au moins il ne se compile pas par défaut à cause d'un include manquant pour aléatoire, et il est alors gribouillé en rouge. Si vous avez l'inclusion par accident, cependant, les choses empirent - VC ++ 2010 le marque toujours comme un mot-clé et n'affiche pas l'info-bulle d'extension de macro, donc aucune aide de l'EDI pour trouver ceci: - /
OregonGhost
J'aime cela! Du pur génie. Imaginez à quel point vous pouvez regarder lorsque vous "Déboguez" cette application alors que personne d'autre n'y est parvenu.
brice
36

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

#define DECLARE_MODIFICATION_REQUEST_PACKET( T )                                                \
namespace NameSpace                                                                     \
{                                                                                       \
                                                                                        \
class T##ElementModificationRequestPacket;                                                          \
}                                                                                       \
                                                                                        \
DECLARE_STREAMING_TEMPLATES( IMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase )    \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( NameSpace::ElementModificationRequestPacket<T> )     \
DECLARE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )      \
                                                                                        \
namespace NameSpace {                                                                   \
class DLLIMPEXP_COMMON T##ModificationRequestPacket : public ElementModificationRequestPacket<T>\
{                                                                                       \
public:                                                                                 \
    T##ModificationRequestPacket( NetBase * pParent )                                   \
    : ElementModificationRequestPacket<T>( pParent ), m_Gen() {}                            \
                                                                                        \
    T##ModificationRequestPacket( NetBase * pParent,                                    \
                            Action          eAction,                                    \
                            const T &   rT )                                            \
    : ElementModificationRequestPacket<T>( pParent, eAction, rT ), m_Gen() {}               \
                                                                                        \
    T##ModificationRequestPacket( const T##ModificationRequestPacket & rhs )                        \
    : ElementModificationRequestPacket<T>( rhs ), m_Gen() {}                                \
                                                                                        \
    virtual                     ~T##ModificationRequestPacket( void ) {}                        \
                                                                                        \
    virtual Uint32          GetPacketTypeID( void ) const                           \
    {                                                                                   \
        return Net::T##_Modification_REQUEST_PACKET;                                        \
    }                                                                                   \
                                                                                        \
    virtual OtherNameSpace::ClassID GetClassID ( void ) const                           \
    {                                                                                   \
        return OtherNameSpace::NetBase::GenerateHeader( OtherNameSpace::ID__LICENSING,  \
                                                         Net::T##_Modification_REQUEST_PACKET );    \
    }                                                                                   \
                                                                                        \
    virtual T##ModificationRequestPacket * Create( void ) const                             \
    { return new T##ModificationRequestPacket( m_pParent ); }                                   \
                                                                                        \
    T##ModificationRequestPacket() {}                                                           \
                                                                                        \
protected:                                                                              \
    OtherNameSpace::ObjectAutogeneration<T##ModificationRequestPacket> m_Gen;                       \
                                                                                        \
    friend class OtherNameSpace::StreamingBase::StreamingClassInfoT<T##ModificationRequestPacket >;                     \
    OtherNameSpace::StreamingBase::Streaming<T##ModificationRequestPacket, ElementModificationRequestPacket<T> >    m_Stream;   \
                                                                                        \
};                                                                                      \
}                                                                                       \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )            \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )            \
typedef  ThirdNameSpace::BroadcasterT<const T##ModificationRequestPacket>  T##ModifiedBroadcaster;



#define IMPLEMENT_MODIFICATION_REQUEST_PACKET( T )                                                                  \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( NameSpace::ElementModificationRequestPacket<T> )                         \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )        \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )        \
INSTANTIATE_STREAMING_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase ) \
INSTANTIATE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )

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é.

Grant Limberg
la source
3
il n'en a évidemment jamais entendu parler: "Le débogage est deux fois plus difficile que l'écriture du code en premier lieu. Par conséquent, si vous écrivez le code aussi intelligemment que possible, vous n'êtes, par définition, pas assez intelligent pour le déboguer." -Brian W.Kernighan
Trevor Boyd Smith
33

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:

LISPID car(LISPID id) {
    CHECK_CONS("car", 1, id);
    return cons_cars[id - CONS_OFFSET];
} /* car */

LISPID cdr(LISPID id) {
    CHECK_CONS("cdr", 1, id);
    return cons_cdrs[id - CONS_OFFSET];
} /* cdr */

(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:

#define car(id) (CHECK_CONS("car", 1, (id)), cons_cars[(id) - CONS_OFFSET])
#define cdr(id) (CHECK_CONS("car", 1, (id)), cons_cdrs[(id) - CONS_OFFSET])

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:

#define CHECK_CONS(fun, pos, arg)   \
    (!IS_CONS(arg) ?        \
        LISP_ERROR("Arg " + pos + " to " + fun +    \
                   " must be a list: " + lispid2string(arg)) : 0)

IS_CONS et LISP_ERROR ont également été utilisés fréquemment, donc je les ai également transformés en macros:

#define IS_CONS(id) \
    (   intp(id) && (id) >= CONS_OFFSET     \
     && ((id) - CONS_OFFSET) < sizeof(cons_cars))

#define LISP_ERROR(str)     (throw((str) + "\n"))

Cela semble raisonnable?

Mais alors, pourquoi tout le système s'est-il écrasé sur cette ligne:

id2 = car(car(car(car((id1))));

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é:

id2 = ((!(intp( (((!(intp( (((!(intp( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
&& ( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) && ( (((!(intp(
(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) >= 1000 && ((
(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (((!(intp( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1))
&& ( (id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars))
Thomas Padron-McCarthy
la source
18
I optimized my code by implementing those [..] functions as macros- derniers mots célèbres ...
BlueRaja - Danny Pflughoeft
3
J'ai commis des abus similaires dans les premières versions de mon interpréteur Postscript. Push and pop étaient les fonctions qui étaient si importantes qu'elles devraient être des macros . Mais composer une expression impliquant plus d'un de ceux-ci conduit à un comportement indéfini. Le comportement non défini n'est détecté que lors de la compilation en -O3. Et à -O3, les versions de fonction auraient été intégrées de toute façon.
luser droog le
29

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:

#define I  Any void_me
#define thou  Any void_thee
#define iam(klas)  klas me = (klas) void_me
#define thouart(klas)  klas thee = (klas) void_thee
#define my  me ->
#define thy  thee ->
#define his  him ->
#define our  my methods ->
#define your  thy methods ->

... qu'il a ensuite utilisé pour écrire des monstruosités telles que:

void Thing_setName (I, const char *name) {
iam (Thing);
if (name != my name) {
    Melder_free (my name);
    my name = Melder_wcsdup (name);
    }
    our nameChanged (me);
}

void Thing_overrideClass (I, void *klas) {
iam (Thing);
my methods = (Thing_Table)klas;
if (! ((Thing_Table) klas) -> destroy)
    ((Thing_Table) klas) -> _initialize (klas);
}

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 ).

Nik Reiman
la source
3
Je suis plutôt charmé par l'anglais possessif et archaïque, pour tout cela bien sûr je suis d'accord que le code a l'air terrible.
Darius Bacon
27

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

   void DisplayLoadError()
   {
   #if defined __TIMETABLE_EDITOR
   MessageBox("Timetable Editor failed to load the correct timetable", MB_ERROR);
   #else if defined __SCHEDULESET_EDITOR
   MessageBox("Schedule Set Editor faied to load the correct Schedule Set", MB_ERROR);
   #else if defined __ROSTER_EDITOR
   MessageBox("Roster Editor failed to load the correct Roster", MB_ERROR);
   #endif
   }
Andrew Shepherd
la source
17

L'utilisation du préprocesseur LINE pour générer un ID unique pour les messages passés sur le réseau:

NetworkMessages.h

#define MSG_LOGIN  __LINE__
#define MSG_LOGOUT __LINE__
#define MSG_CHAT   __LINE__

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é.

MrValdez
la source
8
Et les versions peuvent être incompatibles entre elles (pas bon!). Comment se fait-il qu'une énumération ne suffise pas?
strager
Cela et l'Enum ont exactement le même problème d'incompatibilité.
MrValdez
17
Maintenant, je viens et trie les #defines ... et le protocole change. Ou j'obtiens la religion Doxygen et je documente tous les codes de message, et le protocole change. Au moins une énumération est stable sous ce dernier changement.
RBerteig
3
@MrValdez, il est moins contraignant de garder un bloc d'énumérations dans l'ordre, que de garder les définitions sur les mêmes lignes par rapport au début du fichier.
peterchen
Je sais que c'est un ancien message, mais cela fonctionne-t-il même? Je veux dire que #define remplacera simplement les constantes de message par LINE et alors seulement LINE sera étendu au numéro de ligne, donc chaque fois que nous utilisons la même constante sur différentes lignes - cela changera (au numéro de ligne actuel)?
XzKto
16

Un assez mauvais exemple:

#ifdef __cplusplus
#define class _vclass
#endif

Cela permet à une structure C qui contient une variable membre appelée classd'ê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.

Jonathan Leffler
la source
1
C'est pourquoi Objective-C utilise à la @classplace de class.
14

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 Pdans 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 ...)

Kaz Dragon
la source
12

Je m'ennuyais un jour et je jouais avec des blocs en Objective-C ...

#define Lambda(var, body) [^ id(id (var)) { return (body);} copy]
#define Call(f, arg) ((id(^)(id))(f))(arg)
#define Int(num) [NSNumber numberWithInteger:(num)]
#define Mult(a, b) Int([(a) integerValue] * [(b) integerValue])
#define Add(a, b) Int([(a) integerValue] + [(b) integerValue])
#define Sub1(n) Int([(n) integerValue] - 1)
#define Add1(n) Int([(n) integerValue] + 1)
#define If(cond, thenblock, elseblock) ([(cond) integerValue] ? (thenblock) : (elseblock))
#define Cons(car, cdr_) [[ConsType alloc] initWithCar:(car) cdr:(cdr_)]
#define Car(list) [(list) car]
#define Cdr(list) [(list) cdr]
#define Define(var, value) id var = (value)
#define Nullq(value) Int(value == nil)

autorisant des choses "intéressantes" comme:

Define(Y, Lambda(f, Call(Lambda(x, Call(x, x)),
                         Lambda(x, Call(f, Lambda(y, Call(Call(x, x), y)))))));
Define(AlmostTotal, Lambda(f, Lambda(list, If(Nullq(list), Int(0),
                                              Add(Car(list), Call(f, Cdr(list)))))));
Define(Total, Call(Y, AlmostTotal));
Print(Call(Total, Cons(Int(4), Cons(Int(5), Cons(Int(8), nil)))));

(certaines définitions de fonctions et de classes ne sont pas affichées par souci de concision)

cobbal
la source
"Je me suis ennuyé un jour" derniers mots du célèbre développeur :)
Richard J. Ross III
11

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 ...)

TofuBeer
la source
The code was identical save for the types (so should have used a macro). Non, il aurait dû utiliser un modèle.
BlueRaja - Danny Pflughoeft
1
Il aurait dû utiliser le strcpy intégré! (et c'était du code C pas du C ++ donc pas de modèles) :-P
TofuBeer
L'optimisation prématurée est la racine de tout mal.
Hubert Kario
11

L'obligatoire

#define FOR  for

et

#define ONE  1
#define TWO  2
...

Qui savait?

dcw
la source
5
Mais-mais-mais PAS DE LITERALES DANS LE CODE! ;)
Bernard
ils sont toujours des littéraux mon, devraient les nommer par but / intention et non par symbole alternatif. Code COBOL dont j'ai entendu parler, ils ont fait la variable 5 = 5, puis plus tard ont eu le code disant set 5 = 10 ... les gens étaient vraiment surpris quand ils ont fait var + 5 et ont obtenu var + 10.
Greg Domjan
1
Jamais entendu parler de ça avec COBOL, seulement avec FORTRAN. COBOL, bien sûr, a ZERO, ZEROS et ZEROES comme mots réservés, tous signifiant exactement la même chose que 0.
David Thornley
Bien mieux que "#define ONE 0". Si vous voulez rire, recherchez cela sur le Web et soyez surpris par le nombre de hits différent de zéro.
reuben
11
#define TRUE 0 // dumbass

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:

if (memcpy(buffer, packet, BUFFER_SIZE) == TRUE) {
; // rape that packet
}

Inutile de dire que personne dans notre équipe (testeur ou développeur) n'a jamais osé revoir son code.

Michael Foukarakis
la source
1
Je blâme les fonctions de la bibliothèque C pour avoir fait 0 "tout va bien": P
RCIX
6
Pourquoi ne pas déclarer quelque chose comme #define FLAG_SUCCESS 0?
pyon
11

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.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}
vide
la source
Le pire, c'est lorsque les macros masquent à la fois les gotoinstructions et les définitions des étiquettes cibles. Totalement magique.
reuben
J'en ai souffert - mais les macros ressemblaient à des appels de fonction.
Jonathan Leffler
10
#include <iostream>
#define public_static_void_main(x) int main()
#define System_out_println(x) std::cout << x << std::endl

public_static_void_main(String[] args) {
  System_out_println("Hello World!");
}
Franc
la source
3
Et VOUS vouliez écrire un runtime. Regardez combien de temps j'ai économisé!
Bernard
4
@Trevor: Ouais ... les plus intelligents font toujours Java à la place. court pour la couverture
Michael Myers
Si vous mettez le [] après args au lieu d'avant, et "#define String int argc, char *", il compilera (malheureusement).
Adam Rosenfield
16
J'aime mieux l'autre. Celui-ci montre quelque chose de proche de Java en cours d'écriture avec quelques macros. L'autre montre que Java exact est écrit avec une pléthore de macros et de structures sournoises avec des membres de fonction. Le premier était une blague bon marché, tandis que le second était une blague élaborée et bien réfléchie.
Chris Lutz
10

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

Rubys
la source
9

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 -

 if (asa_open == FALSE) {
asa_open = TRUE;
++number_asa_open;
#if ASA_PRINT
if (number_asa_open == 1) {
  /* open the output file */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
#else
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "w");
#endif
  }
#else /* USER_ASA_OUT */
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (ASA_OUT, "a");
#else
    ptr_asa_out = fopen (ASA_OUT, "w");
#endif
  }
#endif /* USER_ASA_OUT */
} else {
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
  fprintf (ptr_asa_out, "\n\n\t\t number_asa_open = %d\n",
           number_asa_open);
}
#endif /* ASA_PRINT */
} else {
++recursive_asa_open;
#if ASA_PRINT
if (recursive_asa_open == 1) {
  /* open the output file */
#if ASA_SAVE
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
#else /* ASA_SAVE */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {

etc.

Et ce n'est que la configuration des options. tout le programme est comme ça.

Steve
la source
2
Oh mon dieu ... je pense que j'ai le vertige.
Michael Foukarakis