Was ist der schlimmste Missbrauch von Makros / Vorprozessoren in der realen Welt, auf den Sie jemals gestoßen sind?


176

Was ist der schlimmste Missbrauch von Makros / Vorprozessoren in der realen Welt, auf den Sie jemals gestoßen sind (bitte keine erfundenen IOCCC-Antworten * haha ​​*)?

Bitte fügen Sie einen kurzen Ausschnitt oder eine Geschichte hinzu, wenn dies wirklich unterhaltsam ist. Das Ziel ist es, etwas zu lehren, anstatt den Leuten immer zu sagen, dass sie niemals Makros verwenden sollen.


ps: Ich habe vorher Makros verwendet ... aber normalerweise werde ich sie irgendwann los, wenn ich eine "echte" Lösung habe (selbst wenn die echte Lösung inline ist, so dass sie einem Makro ähnelt).


Bonus: Geben Sie ein Beispiel an, in dem das Makro wirklich besser war als eine Nicht-Makro-Lösung.

Verwandte Frage: Wann sind C ++ - Makros von Vorteil?


+1 für die Aufmerksamkeit auf den grassierenden Missbrauch, den ich durch Makros erlitten habe.
i_am_jorf

37
#define true false // glückliches Debuggen :)
n0rd

Community-Wiki bedeutet, dass niemand durch Up / Down-Abstimmungen zu dieser Frage oder ihren Antworten an Ansehen gewinnt (oder verliert). Viele Leute betrachten Fragen wie diese als billige und einfache Möglichkeit, sich einen Namen zu machen. Wenn Sie sie also als Community-Wiki markieren, ist es weniger wahrscheinlich, dass die Leute aus der Form geraten und sie schließen.
Graeme Perrow

2
"Die Leute werden wahrscheinlich alle aus der Form geraten und sie schließen": Wollen Sie damit sagen, dass Sie keinen humorvollen / lustigen Inhalt über den Stapelüberlauf wollen?
Trevor Boyd Smith

2
Nur ein kurzer Punkt, der Vorprozessor ist Teil der Sprache und daher nicht böse / falsch zu benutzen, genau wie alles andere.
Mr. Boy

Antworten:


410

Aus dem Gedächtnis sah es ungefähr so ​​aus:

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

Ja, das stimmt, keine schließenden Klammern in einer der Funktionen. Das Hervorheben der Syntax war ein Chaos, daher verwendete er vi zum Bearbeiten (nicht vim, es hat Syntaxfarben!)

Er war ein russischer Programmierer, der hauptsächlich in Assemblersprache gearbeitet hatte. Er war fanatisch darin, so viele Bytes wie möglich zu speichern, da er zuvor an Systemen mit sehr begrenztem Speicher gearbeitet hatte. "Es war für Satelliten. Nur sehr wenige Bytes, also verwenden wir jedes Byte für viele Dinge." (ein bisschen fummeln, Maschinenbefehlsbytes für ihre numerischen Werte wiederverwenden) Als ich herausfinden wollte, welche Arten von Satelliten es gibt, konnte ich nur "Satelliten umkreisen. Für die Umlaufbahn" erhalten.

Er hatte zwei weitere Macken: Ein konvexer Spiegel über seinem Monitor "Um zu wissen, wer zuschaut" und ein gelegentliches plötzliches Verlassen seines Stuhls, um schnell zehn Liegestütze zu machen. Er erklärte diesen letzten als "Compiler hat Fehler im Code gefunden. Dies ist eine Bestrafung".


87
"Der Compiler hat einen Fehler im Code gefunden. Dies ist eine Bestrafung." !! Firma hat dich gefunden ... Bestrafung der Kollegen!
Lernen

227
In Sowjetrussland stellt das Programm SIE zusammen!
Crashworks

53
Als ich über den Compilerfehler "Bestrafung" las, dachte ich zuerst an "Dobby musste seine Hände bügeln".
Graeme Perrow

124
Ich denke, Programmierer (ich selbst eingeschlossen) wären viel besser geeignet, wenn wir alle jedes Mal 10 Liegestütze machen würden, wenn ein Compiler einen Fehler in unserem Code findet. Dies kann auch das Auftreten von Tests durch Kompilierung verringern.
MikeyB

5
Der Typ klingt großartig. Aber ja, ich verstehe nicht, wie dies die Codegröße verbessern soll.
Jalf

274

Mein schlimmstes:

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

Ich habe zwei Tage meines Lebens damit verbracht, ein Problem mit der COM-Ref-Zählung mit mehreren Threads aufzuspüren, weil ein Idiot dies in eine Header-Datei geschrieben hat. Ich werde die Firma, für die ich damals gearbeitet habe, nicht erwähnen.

Die Moral dieser Geschichte? Wenn Sie etwas nicht verstehen, lesen Sie die Dokumentation und erfahren Sie mehr darüber. Lass es nicht einfach verschwinden.


146
@ Joshua: Wenn Sie diesen Code in einer Multithread-Umgebung ausführen, können Sie dies möglicherweise ungewollt tun
1800 INFORMATION

11
"Wenn Sie etwas nicht verstehen, lesen Sie die Dokumentation und erfahren Sie mehr darüber. Lassen Sie es nicht einfach verschwinden." - AMEN!
Paul Alexander

2
@ 1800 Information: Ich denke, Sie würden nur Stimmen verlieren, weshalb ich Ihnen keine geben kann; p
wkf

5
Verzeihen Sie mir als Nicht-C ++ - Programmierer: Ist das Hauptproblem hier, dass eine threadsichere Funktion in eine nicht threadsichere umgewandelt wird? Oder dass InterlockedIncrement einen Zeiger erwartet, sodass Sie jetzt den Zeiger erhöhen, anstatt auf das, worauf er zeigt? Oder beides?
Tim Pietzcker

38
Das Problem ist, dass InterlockedIncrement normalerweise eine atomare Funktion ist, die in der Windows-API definiert ist. Wenn Benutzer InterlockedIncrement aufrufen, erwarten sie, dass sie eine Funktion aufrufen, die garantiert atomar ausgeführt wird. Stattdessen hat jemand ein Makro mit demselben Namen definiert, das zu einem einfachen,
nichtatomaren

166
#define ever (;;)
for ever { 
   ...
}

52
Ich bevorzuge <#define forever for (;;)>, damit Sie <forever {...}> schreiben können
paxdiablo

Jemand, den ich mit verlorenen Noten für das JEDE Ding zur Schule gegangen bin ... er war erstickt, wie es im Lehrbuch stand :-)
TofuBeer

6
Ist Pax 'Vorschlag nicht direkt von K & R? Trotzdem, die Mühe nicht wert, würde ich sagen.
Jon Ericson

Das ist eigentlich gar nicht so schlecht. Ich verwende kein for (;;)Idiom, sonst würde ich dieses Makro sofort zu meinem Code hinzufügen.
AnT

1
@ Hayalci: In Emacs Lisp (und einigen gängigen Lisp-Implementierungen) könnten Sie (defmacro ever ())und dann(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!");
}

Herausforderung: Kann es jemand mit weniger Definitionen und Strukturen machen? ;-);


19
Sie haben gerade einen Java-zu-C-Konverter geschrieben! horray!
Andreas Petersson

25
Als "beleidigend" gemeldet. (Ich Kind!)
Annika Backstrom

40
Das ist entweder schrecklich schön oder wunderschön schrecklich.
Chris Lutz

38
@Mark - Es deklariert publicund static as nothing, ungültig` als intund main(x)als main()wird so public static void main(String[] args)in int main(). Dann Systemwird in S s;s, also System.out.println("Hello World!");wird in, S s; s.out.println("Hello World!");was die printlnFunktion in der FStruktur in der SStruktur aufruft .
Chris Lutz

2
Schauen Sie sich das an: mailcom.com/ioccc/chia/chia.c (herunterladen und kompilieren)
Roberto Bonvallet

130
#define private public

Das habe ich schon mal gemacht. Manchmal müssen Sie nur eine Mitgliedsvariable ändern oder eine Funktion in einem Code eines Drittanbieters überschreiben, den Sie nicht ändern können - und sie haben keinen Accessor für Sie bereitgestellt.
Michael Kristofik

30
Wow, für Unit-Tests könnte dies sogar nützlich sein, obwohl die Geister des Objektdesigns Sie nachts verfolgen werden.
Epaga

12
Hmmm, undefiniertes Verhalten, leichte Verletzung der One-Definition-Regel, mögliche Layoutunterschiede. Ja, das ist ein Gewinner.
David Thornley

10
Damit kann ich auf private und öffentliche Inhalte zugreifen, jedoch nicht auf geschützte Inhalte, und ich kann nicht auf die Inhalte zwischen dem classSchlüsselwort und dem ersten Zugriffsmodifikator zugreifen.
Ken Bloom

3
@ Ken:#define class struct #define protected public
Yakov Galka

107
#define if while

Es war ein Witz, der jemandem vorgespielt wurde, der von den Betroffenen nicht als amüsant empfunden wurde


22
#define while if wäre noch heimtückischer.
Starblue

7
Wir sollten Ihre Aussage klarstellen. Es wurde von den Betroffenen nicht als amüsant empfunden . :-)
Andrew Shepherd

6
Wenn ich Hausaufgaben machte, machte ich solche Dinge oft absichtlich, nur um meine Lehrer zu ärgern.
pyon

15
Dies ist ein guter Streich, aber er wird nicht kompiliert, wenn es "else" -Anweisungen gibt. Ich habe festgestellt, dass #define if (x) if (true) am effektivsten ist.
Grafik Noob

32
Ich habe immer #define sizeof (x) rand () vorgezogen
Jon

106

Das Schreckliche:

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

Im Ernst, wenn Sie in Pascal codieren möchten, kaufen Sie einen Pascal-Compiler und zerstören Sie nicht die schöne C-Sprache.


45
Jetzt frage ich mich, welche Sprachen ich mit einer ausreichend cleveren Header-Datei simulieren kann.
Bill the Lizard

47
C ist nicht schön. Es ist ziemlich hässlich.
Rlbond

27
Ihre Schönheit liegt in ihrer Einfachheit. Es wurde gesagt, dass es die Geschwindigkeit der Assemblersprache hat, kombiniert mit der Lesbarkeit von ... Assemblersprache :-) Ich bevorzuge es gegenüber dem aufgeblähten C ++ (obwohl ich Java in meiner täglichen Arbeit aufgrund seiner riesigen Bibliothek bevorzuge).
Paxdiablo

9
Nicht wirklich. Finden Sie Bournes Originalquelle für die Bourne-Shell. Er tat genau das, um eine Art Bastard-ALGOL-ähnliches Durcheinander zu bekommen.
RBerteig

3
#define DO für (int _i = 0; _i <= 1; ++ _ i) {if (_i == 1) //// LINE BREAK //// #define IF (cond); if (! (cond)) break; } //// LINE BREAK //// DO printf ("a") IF (1 == 2);
Adrian Panasiuk

93

Ein 'Architekt', ein sehr bescheidener Typ, Sie kennen den Typ, hatte Folgendes:

#define retrun return

weil er gerne schnell tippte. Der Gehirnchirurg schrie gern Leute an, die schlauer waren als er (was so ziemlich jeder war), und drohte, seinen schwarzen Gürtel an ihnen zu tragen.


Ich mache diesen Tippfehler so sehr, dass ich tatsächlich darüber nachgedacht habe.
Joshua

4
Bringen Sie Ihrem Editor stattdessen bei, die automatische Wiedereinstellung in die Rückgabe zu ersetzen. Ich habe meinem IRC-Client zumindest solche Hackeries angetan
Tetha

1
Hey, ich glaube, ich habe auch mit diesem 'Architekten' gearbeitet. Er wurde schließlich als leitender Architekt eingestuft, als er sein Ego besänftigen musste.
BIBD

1
Ich hatte 'rn' in bash in 'rm' neu definiert, weil ich nicht tippen konnte und der 'rn'-Newsreader 5 Minuten brauchte, um zu starten und eine Verbindung zum Server herzustellen.
Martin Beckett

2
Sie konnten nicht einfach ein neues Terminal öffnen (oder zu einem anderen vt wechseln) und tun killall rn?
Joe D

69

Echte Welt? MSVC hat in minmax.h Makros namens maxund min, die jedes Mal einen Compilerfehler verursachen, wenn ich die Standardfunktion verwenden möchte std::numeric_limits<T>::max().


2
Ah, ja, deshalb hatte ich einen speziellen Header mit # undef's zur Wiederherstellung der geistigen Gesundheit nach den MS-spezifischen ...
Pontus Gagge

3
Gelöst mit (std :: numeric_limits <T> :: max) () Aber ja, ziemlich nervig.
Rlbond

36
Fügen Sie NOMINMAX zu Ihren Projekteigenschaften unter C / C ++ -> Präprozessor -> Präprozessordefinitionen hinzu.
Mattnewport

18
Diese Makros waren in den MS-Headern länger als min und max in der C ++ - Standardbibliothek vorhanden.
Richard

4
Es ist noch schlimmer, wenn vier Ihrer anderen externen Abhängigkeiten auch eigene Min / Max-Werte definieren, die unterschiedlich schlecht sind und von schlecht in Klammern gesetzten Makros bis zu gut geschriebenen Vorlagen reichen. Eine davon muss es nur unmöglich machen, undefiniert zu sein oder auf andere Weise überspringen ... In meinem Buch ist die Sprache jedoch zu 50% schuld.
Roman Starkov

58

Eine Mischung aus Pascal-Syntax und französischen Schlüsselwörtern:

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }

36
#define zut_alors exit (-1)
MikeyB

4
Das ist großartig und hat mich laut zum Lachen gebracht. Dies ist also im Grunde eine lokalisierte französische Version von Basic, die in C implementiert ist?
Bobby

56

Raymond Chen hat eine wirklich gute Kritik gegen die Verwendung von Flusskontrollmakros . Sein bestes Beispiel stammt direkt aus dem ursprünglichen Quellcode der 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
}

2
Zwei Punkte: Erstens hat diese Paste die ursprüngliche Einkerbung durcheinander gebracht. Und zweitens sieht der Code gut aus für das, was er ist: Unix C aus den 1970er Jahren von einem begeisterten Algol-68-Fan. Wenn der glückliche Steife sich in einem skurrilen Stil ausdrücken kann, warum kann Steve Bourne dann nicht? Natürlich kann jemand, der dazu verurteilt ist, Algol 68 nicht zu kennen, diese Chance, seinen eigenen Geschmack zu erweitern, nicht schätzen.
Darius Bacon

Ich denke, dies könnte eher als Witz von Steve Bourne als als vorgeschlagener Programmierstil gedacht sein
Martin Beckett

2
Ich habe if... else... elif... fiund case... esacschon einmal gesehen (in der Sprache, die Bourne für sh erfunden hat), aber loop... poolist ein echtes Juwel.
Hobbs

54

Ich möchte für den Wettbewerb ein Juwel namens Chaos- Pp einreichen , das mithilfe der Präprozessor-Makros eine funktionale Sprache implementiert.

Eines der Beispiele ist die Berechnung der 500. Fibonacci-Zahl vollständig durch den Präprozessor:

Der ursprüngliche Code vor dem Präprozessor sieht folgendermaßen aus:

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

Bei der Vorverarbeitung der Datei erhalten wir das folgende Ergebnis (nach einer ziemlich langen Wartezeit):

$ 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;
}

1
Sie können den Code aus CVS abrufen und einen Blick darauf werfen. Ich hatte vor einiger Zeit einige weitere Details in meinen Blogpost aufgenommen, als ich darauf stieß: bnpcs.blogspot.com/2009/02/… Wenn nicht wegen des Problems beim Debuggen des resultierenden Codes (das Problem, wenn ich sehr lange Zeilen habe, wenn Sie werden von einer solchen "Sprache" erzeugt. Sie hätte sogar als praktischer Codegenerator für C verwendet werden können.
Andrew Y

Ich kann mir nur vorstellen, dass das Kompilieren ewig dauert
Paul Fultz II

52

Direkt von Qt:

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

Wirklich schön, mit anderen Bibliotheken als Boost :: -Signalen zu interagieren ... Nur ein Beispiel, es gibt viele andere in Qt, die lustig aussehenden Code erstellen wie:

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

Und das ist C ++ ... aber plötzlich:

boost::signals::trackable

Ist C ++ nicht mehr gültig.


5
:) Es ist also ein Makro, das andere Bibliotheken umsonst kaputt macht. Das ist sogar besser als ich erwartet hatte :)
David Rodríguez - Dribeas

38
Qt ist sehr territorial und wird andere Bibliotheken, die versuchen, ihren Namespace zu besetzen, bösartig angreifen :)
Jeremy Friesner

21
Leider greift Qt Bibliotheken außerhalb seines Namespace mit Makros an
David Rodríguez - Dribeas

7
Glücklicherweise hat boost :: signal2 dieses Problem behoben;)
bdonlan

9
Verwenden Sie Q_SIGNALS und Q_SLOTS, wenn Sie Angst vor dieser Interaktion haben.
Tadeusz A. Kadłubowski

50

Windows.h hat viele Funktionen, die Makros missbraucht haben.


MrValdez ärgert sich über das GetObject-Makro in Windows.h

Das GetObject-Makro ändert die Funktion GetObject () in GetObjectA () oder GetObjectW () (abhängig davon, ob der Build in Nicht-Unicode bzw. Unicode kompiliert wurde).

MrValdez hasst es, vor der GetObject-Funktionszeile arbeiten zu müssen

#undef GetObject

Object *GetObject()

Die Alternative besteht darin, den Funktionsnamen in etwas anderes wie GetGameObject () zu ändern.


jdkoftinoff in den Kommentaren hat es geschafft: Das Problem ist, dass alle Windows-API-Funktionen Makros sind.

Adam Rosenfield erwähnte, dass die Probleme behoben werden können, indem NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX usw. definiert werden, bevor windows.h hinzugefügt wird, um die Probleme zu beseitigen.


3
Sie können dies unterdrücken, aber NOGDI definieren, bevor Sie windows.h einschließen, vorausgesetzt natürlich, Sie müssen keine der verschiedenen GDI-Funktionen verwenden. Es gibt eine Reihe anderer Makros wie WIN32_LEAN_AND_MEAN, NOMINMAX usw., die verhindern, dass andere Dinge definiert oder eingeschlossen werden.
Adam Rosenfield

1
GetObject ist ein ziemlich allgemeiner Funktionsname. Vielleicht hätten Sie angesichts des Kontexts einen aussagekräftigeren Namen verwenden können, um die Kollision zu vermeiden. Dies ist jedoch ein ziemlich böser Makrofall.
Strager

1
Es ist ziemlich ärgerlich, dass win32 über alle Makros verfügt, um API-Namen in FooA und FooW zu konvertieren. Wir haben das Problem mit SendMessage.
i_am_jorf

6
Problem ist, dass alle Windows-API-Funktionen Makros sind. Eines, das mich gebissen hat, war GetTickCount (). Da ich den größten Teil meiner Programmierung außerhalb von Windows durchführe, habe ich alle Definitionen in den Windows-Headern gefunden und dann meine eigene Include-Datei erstellt, in der sie alle definiert wurden, um die Kompatibilität im Voraus zu überprüfen.
jdkoftinoff

12
Ich denke wir haben einen Gewinner. Es ist real, es ist eine lächerlich schlechte Idee und es betrifft eine große Anzahl unschuldiger Programmierer. Wer bei Microsoft für dieses Juwel verantwortlich ist, sollte als Kriegsverbrecher angesehen werden ... Das Beste daran ist, dass Microsoft nicht zweimal darüber nachgedacht hat, so erstaunlich gebräuchliche Namen wie GetObject, SendMessage oder CreateWindow zu verwenden.
Jalf

45
#define return if (std::random(1000) < 2) throw std::exception(); else return

das ist einfach so böse. Es ist zufällig, was bedeutet, dass es die ganze Zeit an verschiedenen Orten ausgelöst wird. Es ändert die return-Anweisung, die normalerweise Code enthält, der von selbst fehlschlagen kann. Es ändert das unschuldig aussehende Schlüsselwort, über das Sie niemals misstrauisch werden, und es wird verwendet Ausnahme vom Standardspeicherplatz, damit Sie nicht versuchen, Ihre Quellen zu durchsuchen, um die Quelle zu finden. Einfach brilliant.


4
Gerade getestet, zumindest wird es nicht standardmäßig kompiliert, da ein zufälliges Include fehlt, und es ist dann rot gekräuselt. Wenn Sie das Include jedoch versehentlich haben, wird es schlimmer - VC ++ 2010 markiert es immer noch als Schlüsselwort und zeigt den Tooltip zur
Makroerweiterung

Ich liebe es! Wahres Genie. Stellen Sie sich vor, wie gut Sie aussehen können, wenn Sie diese Anwendung "debuggen", wenn es sonst niemand geschafft hat.
Brice

36

Ein Mitarbeiter und ich haben diese beiden Juwelen in einem Teil unseres Codes für das Objekt-Streaming gefunden. Diese Makros wurden in JEDEM EINZELNEN instanziiert Klassendatei , die Streaming durchgeführt hat. Dieser abscheuliche Code ist nicht nur in unserer gesamten Codebasis verbreitet, als wir uns an den ursprünglichen Autor wandten, schrieb er einen 7-seitigen Artikel in unserem internen Wiki, in dem er dies als die einzig mögliche Möglichkeit verteidigte, das zu erreichen, was er hier versuchte.

Unnötig zu erwähnen, dass es inzwischen überarbeitet wurde und in unserer Codebasis nicht mehr verwendet wird.

Lassen Sie sich nicht von den hervorgehobenen Schlüsselwörtern abschrecken. Dies ist ALL ein Makro

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

Update (17. Dezember 2009):

Weitere gute Nachrichten bezüglich dieses abscheulichen Makroautors. Ab August wurde der für diese Monstrosität verantwortliche Mitarbeiter entlassen.


3
Offensichtlich hat er noch nie davon gehört: "Das Debuggen ist doppelt so schwierig wie das Schreiben des Codes. Wenn Sie den Code also so geschickt wie möglich schreiben, sind Sie per Definition nicht klug genug, um ihn zu debuggen." -Brian W. Kernighan
Trevor Boyd Smith

33

Ich habe selbst Folgendes getan und ich glaube, ich habe etwas daraus gelernt.

Ungefähr 1992 schrieb ich einen kleinen Lisp-Dolmetscher. Es wurde nicht in normalem C implementiert, sondern in einer interpretierten C-ähnlichen Sprache. Diese C-ähnliche Sprache verwendete jedoch den Standard-C-Vorprozessor.

Der Lisp-Interpreter enthielt natürlich die Funktionen car , die in Lisp verwendet werden, um das erste Element in einer Liste zurückzugeben, und cdr , das den Rest der Liste zurückgibt. Sie wurden folgendermaßen umgesetzt:

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 */

(Daten wurden in Arrays gespeichert, da keine Strukturen vorhanden waren. CONS_OFFSET ist die Konstante 1000.)

car und cdr werden in Lisp häufig verwendet und sind kurz. Da Funktionsaufrufe in der Implementierungssprache nicht sehr schnell waren, habe ich meinen Code optimiert, indem ich diese beiden Lisp-Funktionen als Makros implementiert habe:

#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 prüft, ob es sich bei dem Argument tatsächlich um eine Liste handelt. Da dieses Argument auch häufig im Interpreter verwendet wird und kurz ist, habe ich dieses Argument auch als Makro geschrieben:

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

IS_CONS und LISP_ERROR wurden ebenfalls häufig verwendet, daher habe ich sie auch zu Makros gemacht:

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

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

Scheint vernünftig?

Aber warum stürzte dann das gesamte System in dieser Zeile ab:

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

Ich habe lange gearbeitet, um das Problem zu finden, bis ich schließlich überprüfte, wozu diese kurze Zeile vom Vorprozessor erweitert wurde. Es wurde zu einer Zeile mit 31370 Zeichen erweitert, die ich hier aus Gründen der Übersichtlichkeit in Zeilen (502 davon) aufgeteilt habe:

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

18
I optimized my code by implementing those [..] functions as macros- berühmte letzte Worte ...
BlueRaja - Danny Pflughoeft

3
Ich habe in früheren Versionen meines Postscript-Interpreters ähnliche Missbräuche begangen. Push und Pop waren die Funktionen, die so wichtig waren, dass sie Makros sein sollten . Das Verfassen eines Ausdrucks mit mehr als einem dieser Ausdrücke führt jedoch zu undefiniertem Verhalten. Das undefinierte Verhalten wird nur beim Kompilieren bei -O3 abgefangen. Und bei -O3 wären die Funktionsversionen sowieso eingefügt worden.
Luser Droog

29

Ich musste einmal eine C-Anwendung von Unix auf Windows portieren, deren spezifische Natur zum Schutz der Schuldigen unbenannt bleiben soll. Der Typ, der es schrieb, war ein Professor, der nicht daran gewöhnt war, Produktionscode zu schreiben, und der eindeutig aus einer anderen Sprache zu C gekommen war. Es kommt auch vor, dass Englisch nicht seine Muttersprache war, obwohl das Land, aus dem er stammte, die Mehrheit der Menschen es recht gut spricht.

In seiner Anwendung wurde der Präprozessor stark genutzt, um die C-Sprache in ein Format zu verwandeln, das er besser verstehen konnte. Die Makros, die er am häufigsten verwendete, wurden jedoch in einer Header-Datei mit dem Namen 'Thing.h' (ernsthaft) definiert, die Folgendes enthielt:

#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 ->

... mit denen er dann Monstrositäten wie die folgenden schrieb:

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);
}

Das gesamte Projekt (~ 60.000 LOC) wurde in einem ähnlichen Stil geschrieben - Marco Hell, seltsame Namen, alt-englischer Jargon usw. Glücklicherweise konnten wir den Code wegwerfen, da ich eine OSS-Bibliothek gefunden habe, die den gleichen Algorithmus Dutzende ausführte mal schneller.

(Ich habe diese Antwort, die ich ursprünglich auf diese Frage gemacht habe, kopiert und bearbeitet .)


3
Ich bin ziemlich entzückt von den Possessiven und dem archaischen Englisch, trotzdem stimme ich natürlich zu, dass der Code schrecklich aussieht.
Darius Bacon

27

Das Schlimmste, dem ich je begegnet bin, war ein Produkt mit einer Reihe ausführbarer Dateien, bei denen der designierte technische Leiter keine Bibliotheken herausgefunden hatte.

Stattdessen verfügte er über Dateigruppen, die in mehreren Visual Source Safe-Ordnern gemeinsam genutzt wurden. Dann erkannte er, dass sie sich für jede Anwendung etwas anders verhalten mussten.

Es gibt eine Reihe von Refactoring-Schritten, die Sie hier anwenden können.

Stattdessen verwendete er #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
   }

17

Die Verwendung des LINE-Präprozessors zum Generieren einer eindeutigen ID für Nachrichten, die über das Netzwerk übertragen werden:

NetworkMessages.h

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

Dies ist ein Beispiel, in dem das Makro wirklich besser war als eine Nicht-Makro-Lösung:

In einer Nicht-Makro-Lösungsklasse müssen Funktionen und Variablen erstellt werden, um zu verfolgen, welche ID die Nachricht ist. Der Entwickler kann die Verfolgung der Nachrichten-ID möglicherweise kompliziert machen oder nicht, während dies einfacher zu lesen und zu debuggen ist.

Darüber hinaus ist es einfacher, neue Nachrichten hinzuzufügen, indem Sie die Nachricht einfach zur Quelle hinzufügen.

Der Nachteil dieser Situation ist, dass die Datei in allen Codes enthalten sein muss, die Nachrichten verwenden. Die Kompilierungszeit erhöht sich, wenn eine Nachricht bearbeitet wird.


8
Und Versionen sind möglicherweise nicht miteinander kompatibel (nicht gut!). Wie kommt es, dass eine Aufzählung nicht ausreicht?
Strager

Sowohl dies als auch die Aufzählung haben genau das gleiche Problem der Inkompatibilität.
MrValdez

17
Jetzt komme ich vorbei und sortiere die #defines ... und das Protokoll ändert sich. Oder ich bekomme die Doxygen-Religion und dokumentiere alle Nachrichtencodes und die Protokolländerungen. Zumindest eine Aufzählung ist unter der letzteren Änderung stabil.
RBerteig

3
@ MrValdez, es ist weniger restriktiv, einen Block von Aufzählungen in der richtigen Reihenfolge zu halten, als Definitionen in Bezug auf den Dateistart in denselben Zeilen zu halten.
Peterchen

Ich weiß, dass dies ein alter Beitrag ist, aber funktioniert das überhaupt? Ich meine, #define ersetzt nur die Nachrichtenkonstanten durch LINE und erst dann wird LINE auf die Zeilennummer erweitert. Jedes Mal, wenn wir dieselbe Konstante in verschiedenen Zeilen verwenden, ändert sich dies (auf die aktuelle Zeilennummer).
XzKto

16

Ein ziemlich schlechtes Beispiel:

#ifdef __cplusplus
#define class _vclass
#endif

Dadurch kann eine C-Struktur, die eine aufgerufene Mitgliedsvariable enthält class, von einem C ++ - Compiler verarbeitet werden. Es gibt zwei Header mit diesem Konstrukt; einer von ihnen enthält am Ende auch '#undef class' und der andere nicht.


1
Aus diesem Grund verwendet Objective-C @classanstelle von class.

14

In einem Jahr des Internationalen Wettbewerbs für verschleierte C-Codierung gab es einen Eintrag, in dem das gesamte Programm enthalten war:

P

Mit der Maßgabe, dass Sie Pim Makefile definieren können, welches Programm Sie möchten.

Soweit ich mich erinnere, hat es in einer der Kategorien gewonnen, und im nächsten Jahr war eine Regel aufgetaucht, die diesen Eintrittsstil nicht zuließ.

(Bearbeiten: sechs Monate später oder so ... Ich bin sicher, dass das "No IOCCC" -Ding nicht in der Hauptfrage war, als ich das schrieb ...)


12

Ich war eines Tages gelangweilt und spielte mit Blöcken in 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)

"interessante" Dinge zulassen wie:

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

(Einige Funktions- und Klassendefinitionen werden der Kürze halber nicht angezeigt.)


"Ich war eines Tages gelangweilt" berühmte Entwickler letzte Worte :)
Richard J. Ross III

11

Das Schlimmste, was ich gesehen habe, war die Nichtbenutzung :-)

Jemand hat eine strcpy-Funktion (ich glaube, das war es ... vor über 10 Jahren) innerhalb einer Methode geschrieben (weil sie nicht den Aufwand haben wollten, strcpy aufzurufen ... seufz).

Sie wiesen darauf hin, dass es für japanische Zeichen nicht funktionieren würde, und fügten zu Beginn ein "Wenn" hinzu, um ASCII oder Unicode auszuführen. Zu diesem Zeitpunkt war der Code ungefähr ein Bildschirm lang ... wahrscheinlich wurde die Cache-Kohärenz zerstört und seine angeblichen Ersparnisse für das Inlining des Codes gelöscht.

Der Code war bis auf die Typen identisch (hätte also ein Makro verwenden sollen).

Natürlich war der Strcpy, den sie geschrieben haben, viel viel langsamer als der handgestimmte Assembler, der sich in der Standardbibliothek befand ...

Wenn sie alles nur als Makro gemacht hätten, hätte es natürlich durch einen Aufruf von strcpy ersetzt werden können ...

Natürlich habe ich die Firma verlassen (nicht direkt deswegen ...)


The code was identical save for the types (so should have used a macro).Nein, er hätte eine Vorlage verwenden sollen.
BlueRaja - Danny Pflughoeft

1
Er hätte das eingebaute strcpy benutzen sollen! (und es war C-Code nicht C ++, also keine Vorlagen) :-P
TofuBeer

Vorzeitige Optimierung ist die Wurzel allen Übels.
Hubert Kario

11

Das obligatorische

#define FOR  for

und

#define ONE  1
#define TWO  2
...

Wer wusste?


5
Aber-aber-aber KEINE LITERALE IM CODE! ;)
Bernard

Sie sind immer noch wörtlich mon, sollten sie nach Zweck / Absicht benennen und kein alternatives Symbol. COBOL-Code Ich habe gehört, dass sie die Variable 5 = 5 gemacht haben und später den Code 5 = 10 hatten ... Leute waren wirklich überrascht, als sie var + 5 machten und var + 10 bekamen.
Greg Domjan

1
Ich habe noch nie mit COBOL davon gehört, nur mit FORTRAN. COBOL hat natürlich NULL, NULL und NULL als reservierte Wörter, die alle genau dasselbe bedeuten wie 0.
David Thornley

Viel besser als "#define ONE 0". Wenn Sie kichern möchten, suchen Sie im Internet danach und lassen Sie sich von der Anzahl der Treffer ungleich Null überraschen.
Ruben

11
#define TRUE 0 // dumbass

Die Person, die dies tat, erklärte sich einige Jahre später - die meisten (wenn nicht alle) C-Bibliotheksfunktionen geben 0 zurück, um anzuzeigen, dass alles gut gelaufen ist. Also wollte er Code schreiben können wie:

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

Unnötig zu erwähnen, dass niemand in unserem Team (Tester oder Entwickler) es jemals gewagt hat, noch einmal einen Blick auf seinen Code zu werfen.


1
Ich beschuldige die C-Bibliotheksfunktionen, 0 "alles ist in Ordnung" zu machen: P
RCIX

6
Warum nicht so etwas deklarieren #define FLAG_SUCCESS 0?
Pyon

11

Ich pflege Code, der in Makros gotos enthält. Eine Funktion hat also am Ende eine Beschriftung, aber keinen sichtbaren Punkt im Funktionscode. Um die Sache noch schlimmer zu machen, befindet sich das Makro am Ende anderer Anweisungen, die normalerweise nicht auf dem Bildschirm angezeigt werden, es sei denn, Sie scrollen horizontal.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}

Schlimmer ist, wenn Makros sowohl die gotoAnweisungen als auch die Definitionen der Zielbezeichnungen ausblenden . Total magisch.
Ruben

Ich habe darunter gelitten - aber die Makros sahen aus wie Funktionsaufrufe.
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!");
}

3
Und DU wolltest eine Laufzeit schreiben. Schau dir an, wie viel Zeit ich gespart habe!
Bernard

4
@ Trevor: Ja ... die Schlauen machen stattdessen immer noch Java. läuft in Deckung
Michael Myers

Wenn Sie das [] nach args anstelle von vor und "#define String int argc, char *" setzen, wird es (leider) kompiliert.
Adam Rosenfield

16
Ich mag den anderen besser. Dieser zeigt etwas in der Nähe von Java, das mit ein paar Makros geschrieben wird. Das andere zeigt, wie genau Java mit einer Vielzahl von hinterhältigen Makros und Strukturen mit Funktionselementen geschrieben wird. Der erste war ein billiger Witz, während der zweite ein aufwändiger und durchdachter Witz war.
Chris Lutz

10

Von einem Klassenkameraden, der die Regeln für magische Zahlen nicht verstanden hat:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1


9

ASA - http://www.ingber.com/#ASA

Sie müssen es wirklich herunterladen, um es zu schätzen. Der gesamte Arbeitsablauf wird durch Makros bestimmt. Es ist völlig unlesbar. Als Beispiel -

 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 {

usw. usw.

Und das ist nur das Einrichten der Optionen. Das gesamte Programm ist so.


2
Oh mein Gott ... mir wird schwindelig.
Michael Foukarakis
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.