Präprozessor überlisten, aber wie?
-
Hallo Forumsbesucher,
ich versuche gerade den Umstand zu umgehen, daß in einem Macro mit Parametern kein #define stehen darf. Im Prinzip will ich erreichen, daß letztlich ein
#define token othertoken
dasteht und beim nächsten Lauf aufgelöst wird (der Compiler macht ohne Murren 8 Ersetzungsebenen). Mein Macroversuch dazu
#define CREATE(token) #define token othertoken CREATE(Symbol)
wird beim Macroaufruf mit
error #1056: # not followed by macro parameter.
verweigert. Token- Ersetzungen ohne Parameter klappen hingegen auch mit #- Symbol.
Gibt's da irgendeinen Trick, sowas doch hinzukriegen oder ist das aussichtslos?
Danke für's Nachdenken!
-
pointercrash() schrieb:
Token- Ersetzungen ohne Parameter klappen hingegen auch mit #- Symbol.
Das stimmt zwar, aber dann wird nicht weiter aufgelöst. Also ein Macro samt Aufruf
#define INTERRUPT #pragma interrupt #define Ticker Ticker_y INTERRUPT Ticker
wird zu:
#pragma interrupt Ticker_y
Ab da geht's nicht weiter, weil das #pragma einen Whitespace am Zeilenanfang enthält, es wird also kein Interrupt- Entry- Code für die Funktion Ticker_y erzeugt ==
Mit #define gibt es analog genau die gleichen Probleme.
Hat denn keiner einen Rat, wie ich doch noch hinbekommen kann, daß solche Ersetzungen fortlaufen?
-
pointercrash() schrieb:
ich versuche gerade den Umstand zu umgehen, daß in einem Macro mit Parametern kein #define stehen darf.
das könnte vielleicht klappen, wenn du den präprozessor zweimal drüberlaufen lässt, ansonsten bekommt der compiler das #define zu sehen, was der präprozzi soeben erzeugt hat (womit er natürlich nichts anfangen kann). für pragmas kennt C99 ein _Pragma (mit unterstrich und P gross), das man auch in makros verwenden kann.
-
;fricky schrieb:
das könnte vielleicht klappen, wenn du den präprozessor zweimal drüberlaufen lässt,
Das wär' maximal häßlich, wenn's funktionieren würde, weil ich dann jeden build nicht über die IDE, sondern eigene Scripte anstoßen müsste. Ich mag mir ja nicht Mehrarbeit machen, sondern Faulenzen
. Gotteseidank funktioniert es nicht, weil der Präppi Zeilen mit Anfangs- Whitespaces generell ignoriert.
;fricky schrieb:
... für pragmas kennt C99 ein _Pragma (mit unterstrich und P gross), das man auch in makros verwenden kann.
Funzt bei beiden Hauptkameraden nicht. Dazu wäre noch ein _Define nötig, um die Sache schlüssig zu machen. Mit C99 geht man eh auf dünnes Eis wg. uneinheitlicher Compiler- Unterstützung, muss nicht sein.
Ah, irgendwie komm' ich aus dem Problem nicht raus, generische Funktionen mittels Tokentausch zu multiplizieren. Mittels Runtime- Unterscheidung wär's zwar auch lösbar, aber bedeutet dann doch Großbaustelle im Code plus schnellerer Maschine nötig. Hätte ich gerne vermieden ...
-
pointercrash() schrieb:
Ah, irgendwie komm' ich aus dem Problem nicht raus, generische Funktionen mittels Tokentausch zu multiplizieren.
das geht ja im prinzip. ein (etwas sinnfreies aber lauffähiges) beispiel:
#define MAKE_LEN(name) unsigned len_##name(void){char *q; for (q=name;*q;q++); return (unsigned)(q-name);} #define GET_LEN(name) len_##name() char *hello = "hello"; MAKE_LEN(hello) // ein eigenes strlen für hello char *noch_eins = "noch eins"; MAKE_LEN(noch_eins) // ein eigenes strlen für noch_eins void main (void) { printf ("%d\n", GET_LEN(hello)); printf ("%d\n", GET_LEN(noch_eins)); }
^^nur nicht, wenn der präpro selber präpro-anweisungen machen soll.
-
;fricky schrieb:
^^nur nicht, wenn der präpro selber präpro-anweisungen machen soll.
Ja, genau das wollte ich eigentlich; gut, geht halt nicht, muß ich halt mit expliziten pragmas leben.
Was die anderen Ersetzungen anbelangt, hab' ich sowas zusammengebastelt:#define BIND(token1, token2) token1##_##token2 #define REPLACE(literal1, literal2) BIND(literal1, literal2) #define SYM(token) REPLACE(token, EXTENSION) #define EXTENSION x #pragma interrupt Ticker_x #include "gstep.c" #undef EXTENSION #define EXTENSION y #pragma interrupt Ticker_y #include "gstep.c"
In gstep.c stehen dann halt so lauter #define symbol SYM(symbol), Ticker wär' so ein generischer Funktionsname, funktioniert soweit prima.
Was ich überhaupt nicht verstehe, wenn ich innerhalb ^^^^ dieser ^^^^ Source das #undef EXTENSION weglasse beschwert sich der Präppi völlig zurecht, daß ein doppelter define vorliegt.
Vergesse ich das innerhalb der inkludierten Datei gstep.c, juckt ihn das nicht die Bohne. Also mit dem ersten include erwacht Funktion Ticker_x zum Leben, mit dem zweiten Ticker_y, obwohl ich kein #undef für Ticker drinhabe.Ich dachte, #include wäre nur rein textuell tätig und angelegte Ersetzungen wären persistent, bis ich sie per undef aufhebe.
Nicht, daß ich was dagegen hätte, mir 'nen Haufen Tipparbeit zu sparen, aber es wirkt auf mich zutiefst unlogisch - und das mag ich nicht.
Gibt es dafür eine Erklärung?
-
pointercrash() schrieb:
;fricky schrieb:
^^nur nicht, wenn der präpro selber präpro-anweisungen machen soll.
Ja, genau das wollte ich eigentlich; gut, geht halt nicht, muß ich halt mit expliziten pragmas leben.
naja, der präppi rauscht in der regel nur einmal durch 'ne C-datei. wenn irgendeine chance bestehen soll, dass er die neu erzeugten #defines auch noch bearbeitet, dann musste ihn ein zweitesmal drüberlaufen lassen (wie schon erwähnt).
pointercrash() schrieb:
Vergesse ich das innerhalb der inkludierten Datei gstep.c, juckt ihn das nicht die Bohne. Also mit dem ersten include erwacht Funktion Ticker_x zum Leben, mit dem zweiten Ticker_y, obwohl ich kein #undef für Ticker drinhabe.
C-dateien zu #includen verstösst ohnehin gegen die gut sitten *fg*, vielleicht erzeugst du irgendein undefiniertes verhalten damit? C ist ja berüchtigt dafür.
-
;fricky schrieb:
... dass er die neu erzeugten #defines auch noch bearbeitet, dann musste ihn ein zweitesmal drüberlaufen lassen (wie schon erwähnt).
Automatisiert geht da nix über die IDEs. Irgendwie mit Batches rumfummeln, die mir das Zeug nach dem ersten Lauf in das "Endmontageprojekt" kopieren und dort umbenennen, huh, "Schuß von Hinten durch's Knie in's Hirn" nennt man sowas.
;fricky schrieb:
C-dateien zu #includen verstösst ohnehin gegen die gut sitten *fg*, vielleicht erzeugst du irgendein undefiniertes verhalten damit? C ist ja berüchtigt dafür.
Jaja, heißt jetzt nur deswegen ".c", damit ich mit der IDE direkt auf die Source der Funktionsentries springen kann. Mit ".inc" oder ".txt" macht's keinen Unterschied, nur daß mir die IDE die Funktionen nicht mehr listet, kein Syntaxhighlighting macht etc. Aber zumindest scheint das Verhalten systematisch zu sein.
Getestet habe ich nach dem Pelle jetzt auch einen zweiten Compiler, den Watcom, der verhält sich genauso, bemängelt die Mehrfachdefinition also auch nicht. Embedded- Kisten kann ich derzeit nicht testen, weil die Platte mit den VMs abgeraucht ist und ich erstmal alles aus den Archiven ziehen muß.
Ich kann halt nur nicht "in" den Includes debuggen - ansonsten verhält sich das Teil wie erwünscht. Wenn man im Disasm- Mode debugged, geht's sogar ganz normal.
Also die Regel, daß #include wie eine textuelle Ersetzung zu behandeln ist, stimmt zumindest zwar, weil es egal war, ob ich in der aufrufenden main die #define hatte oder in der gstep.inc, aber echt Sinn macht das immer noch nicht. Es funktioniert zumindest mit zwei Compilern, aber wohler wäre mir schon, wenn ich einen "general ack" auf "kapieren"- Basis herstellen könnte.