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?
c++
c
macros
preprocessor
Trevor Boyd Smith
quelle
quelle
Antworten:
Aus dem Gedächtnis sah es ungefähr so aus:
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".
quelle
Mein schlimmstes:
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.
quelle
quelle
for (;;)
Idiom, sonst würde ich dieses Makro sofort zu meinem Code hinzufügen.(defmacro ever ())
und dann(require 'cl (ever))
Herausforderung: Kann es jemand mit weniger Definitionen und Strukturen machen? ;-);
quelle
public
undstatic as nothing,
ungültig` alsint
undmain(x)
alsmain()
wird sopublic static void main(String[] args)
inint main()
. DannSystem
wird inS s;s
, alsoSystem.out.println("Hello World!");
wird in,S s; s.out.println("Hello World!");
was dieprintln
Funktion in derF
Struktur in derS
Struktur aufruft .quelle
class
Schlüsselwort und dem ersten Zugriffsmodifikator zugreifen.#define class struct #define protected public
Es war ein Witz, der jemandem vorgespielt wurde, der von den Betroffenen nicht als amüsant empfunden wurde
quelle
Das Schreckliche:
Im Ernst, wenn Sie in Pascal codieren möchten, kaufen Sie einen Pascal-Compiler und zerstören Sie nicht die schöne C-Sprache.
quelle
Ein 'Architekt', ein sehr bescheidener Typ, Sie kennen den Typ, hatte Folgendes:
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.
quelle
killall rn
?Echte Welt? MSVC hat in minmax.h Makros namens
max
undmin
, die jedes Mal einen Compilerfehler verursachen, wenn ich die Standardfunktion verwenden möchtestd::numeric_limits<T>::max()
.quelle
Eine Mischung aus Pascal-Syntax und französischen Schlüsselwörtern:
quelle
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:
quelle
if
...else
...elif
...fi
undcase
...esac
schon einmal gesehen (in der Sprache, die Bourne für sh erfunden hat), aberloop
...pool
ist ein echtes Juwel.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:
Bei der Vorverarbeitung der Datei erhalten wir das folgende Ergebnis (nach einer ziemlich langen Wartezeit):
quelle
Direkt von Qt:
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:
Und das ist C ++ ... aber plötzlich:
Ist C ++ nicht mehr gültig.
quelle
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
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.
quelle
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.
quelle
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
Update (17. Dezember 2009):
Weitere gute Nachrichten bezüglich dieses abscheulichen Makroautors. Ab August wurde der für diese Monstrosität verantwortliche Mitarbeiter entlassen.
quelle
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:
(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:
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:
IS_CONS und LISP_ERROR wurden ebenfalls häufig verwendet, daher habe ich sie auch zu Makros gemacht:
Scheint vernünftig?
Aber warum stürzte dann das gesamte System in dieser Zeile ab:
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:
quelle
I optimized my code by implementing those [..] functions as macros
- berühmte letzte Worte ...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:
... mit denen er dann Monstrositäten wie die folgenden schrieb:
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 .)
quelle
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
quelle
Die Verwendung des LINE-Präprozessors zum Generieren einer eindeutigen ID für Nachrichten, die über das Netzwerk übertragen werden:
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.
quelle
Ein ziemlich schlechtes Beispiel:
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.quelle
@class
anstelle vonclass
.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
P
im 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 ...)
quelle
Ich war eines Tages gelangweilt und spielte mit Blöcken in Objective-C ...
"interessante" Dinge zulassen wie:
(Einige Funktions- und Klassendefinitionen werden der Kürze halber nicht angezeigt.)
quelle
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 ...)
quelle
The code was identical save for the types (so should have used a macro).
Nein, er hätte eine Vorlage verwenden sollen.Das obligatorische
und
Wer wusste?
quelle
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:
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.
quelle
#define FLAG_SUCCESS 0
?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.
quelle
goto
Anweisungen als auch die Definitionen der Zielbezeichnungen ausblenden . Total magisch.quelle
Von einem Klassenkameraden, der die Regeln für magische Zahlen nicht verstanden hat:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1
quelle
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 -
usw. usw.
Und das ist nur das Einrichten der Optionen. Das gesamte Programm ist so.
quelle