Ursprüngliche Frage
Was ich möchte, ist kein Standard-C-Präprozessor, sondern eine Variation davon, die von irgendwoher – wahrscheinlich der Befehlszeile über die Optionen -DNAME1 und -UNAME2 – eine Spezifikation akzeptieren würde, welche Makros definiert sind, und dann tot eliminieren würde Code.
Mit einigen Beispielen ist es vielleicht einfacher zu verstehen, wonach ich suche:
#ifdef NAME1
#define ALBUQUERQUE "ambidextrous"
#else
#define PHANTASMAGORIA "ghostly"
#endif
Wenn der Befehl mit ‘-DNAME1’ ausgeführt würde, wäre die Ausgabe:
#define ALBUQUERQUE "ambidextrous"
Wenn der Befehl mit ‘-UNAME1’ ausgeführt würde, wäre die Ausgabe:
#define PHANTASMAGORIA "ghostly"
Wenn der Befehl ohne beide Optionen ausgeführt würde, wäre die Ausgabe dieselbe wie die Eingabe.
Dies ist ein einfacher Fall – ich würde hoffen, dass der Code auch komplexere Fälle handhaben könnte.
Zur Veranschaulichung mit einem realen, aber immer noch einfachen Beispiel:
#ifdef USE_VOID
#ifdef PLATFORM1
#define VOID void
#else
#undef VOID
typedef void VOID;
#endif /* PLATFORM1 */
typedef void * VOIDPTR;
#else
typedef mint VOID;
typedef char * VOIDPTR;
#endif /* USE_VOID */
Ich möchte den Befehl mit ausführen -DUSE_VOID -UPLATFORM1
und bekomme die Ausgabe:
#undef VOID
typedef void VOID;
typedef void * VOIDPTR;
Ein anderes Beispiel:
#ifndef DOUBLEPAD
#if (defined NT) || (defined OLDUNIX)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
Idealerweise würde ich gerne mit laufen -UOLDUNIX
und bekomme die Ausgabe:
#ifndef DOUBLEPAD
#if (defined NT)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
Das könnte mein Glück auf die Probe stellen!
Motivation: große, alte Codebasis mit viel bedingtem Code. Viele der Bedingungen gelten nicht mehr – die OLDUNIX-Plattform zum Beispiel wird nicht mehr hergestellt und nicht mehr unterstützt, daher besteht keine Notwendigkeit, im Code darauf zu verweisen. Andere Bedingungen sind immer wahr. Beispielsweise werden Funktionen mit bedingter Kompilierung hinzugefügt, sodass eine einzige Version des Codes sowohl für ältere Versionen der Software, in denen die Funktion nicht verfügbar ist, als auch für neuere Versionen, in denen sie (mehr oder weniger) verfügbar ist, verwendet werden kann. Schließlich werden die alten Versionen ohne die Funktion nicht mehr unterstützt – alles verwendet die Funktion – also sollte die Bedingung, ob die Funktion vorhanden ist oder nicht, entfernt werden, und der Code „wenn die Funktion fehlt“ sollte ebenfalls entfernt werden. Ich hätte gerne ein Tool, das die Arbeit automatisch erledigt, da es schneller und zuverlässiger ist als die manuelle Ausführung (was ziemlich kritisch ist, wenn die Codebasis 21.500 Quelldateien enthält).
(Eine wirklich clevere Version des Tools könnte lauten #include
‘d-Dateien, um festzustellen, ob die Steuerungsmakros – die durch -D oder -U in der Befehlszeile angegeben werden – in diesen Dateien definiert sind. Ich bin mir nicht sicher, ob das wirklich hilfreich ist, außer als Backup-Diagnose. Was auch immer er sonst tut, der Pseudo-Präprozessor darf Makros nicht erweitern oder Dateien wörtlich einschließen. Die Ausgabe muss eine ähnliche Quelle sein wie der Eingabecode, aber normalerweise einfacher als dieser.)
Statusbericht (ein Jahr später)
Nach einem Jahr Nutzung bin ich sehr zufrieden mit ‘sunifdef‘ von der ausgewählten Antwort empfohlen. Es hat noch keinen Fehler gemacht, und ich erwarte es auch nicht. Der einzige Makel, den ich damit habe, ist stilistisch. Bei einer Eingabe wie:
#if (defined(A) && defined(B)) || defined(C) || (defined(D) && defined(E))
und mit ‘-UC’ ausführen (C ist nie definiert), die Ausgabe ist:
#if defined(A) && defined(B) || defined(D) && defined(E)
Das ist technisch korrekt, weil ‘&&’ enger bindet als ‘||’, aber es ist eine offene Einladung zur Verwirrung. Ich würde es vorziehen, Klammern um die Sätze von ‘&&’-Bedingungen einzuschließen, wie im Original:
#if (defined(A) && defined(B)) || (defined(D) && defined(E))
Angesichts der Unklarheit einiger Codes, mit denen ich arbeiten muss, ist es jedoch ein großes Kompliment, dass dies der größte Nit-Pick ist. es ist ein wertvolles Werkzeug für mich.
Das neue Kind auf dem Block
Nachdem ich die URL für die Aufnahme in die obigen Informationen überprüft habe, sehe ich, dass (wie vorhergesagt) ein neues Programm aufgerufen wird Coan das ist der Nachfolger von ‘sunifdef’. Es ist seit Januar 2010 auf SourceForge erhältlich. Ich werde es mir ansehen … weitere Berichte später in diesem Jahr oder vielleicht nächstes Jahr oder irgendwann oder nie.
Danke für den Vorschlag – nein, das brauche ich nicht. Ich weiß, wie man sich ansieht, was der Compiler sieht (ich habe neulich ein paar Stunden damit verbracht, mir 37.000 Zeilen erweiterter Ausgabe anzusehen, um herauszufinden, warum etwas schief gelaufen ist). Ich möchte, dass #include und andere Zeilen erhalten bleiben und Makros nicht erweitert werden.
– Jonathan Leffler
8. Februar 2009 um 6:58 Uhr