Multiline Makrofunktionen
-
was mir aufgefallen ist: in deinem QUE_POP() makro versuchst du aus dem {} einen wert herauszugeben (returnedValue). ich glaub' das geht nicht. ist mir auch nicht klar, warum gcc sowas frisst (ich bin aber auch nicht so der super makro experte...)
btw: lustig: 'Wichtelstudio'
-
Das geht definitiv nicht (höchsten bei irgendwelchen Exoten-Compilern), Makros machen per Definition nur eine reine textuelle Ersetzung.
Hallo @net, da waren wir uns doch einig. Ich dachte auch schon, dass wir jetzt die Lösung haben
-
jox schrieb:
Hallo @net, da waren wir uns doch einig. Ich dachte auch schon, dass wir jetzt die Lösung haben
für die STRLEN() semantik? naja, so geht's nicht. man könnte es so schreiben
#define STRLEN(x) returnedvalue;{...irgendein_code...;...;}
aber leider wird dabei der code nach der zuweisung ausgeführt
ich wüsste jetzt auch nix für:x = {...code...}
aber vielleicht gibt's da was nur kommen wir nicht drauf...
-
ich habe die Lösung mittlerweile.
Der Grund wieso VS (damit volkard sich nicht beleidgt fühlt) mit meiner Makrodefinition nicht zurecht kommt ist, weil Microsoft sich immer noch keine Mühe gemacht hat den C99 Standard zu implementieren, was bei GCC schon längst der Fall ist. Vielleicht nicht komplett, aber immerhin viel mehr als bei VS.
Eine kleine Bemerkung am Rande - Microsoft und Borland haben offensichtlich nicht vor, C99 jemals zu unterstützen (Zitat von http://www.schellong.de/better_c99.htm).Dieser Standard erlaubt es unter Anderem Makros zu schreiben, die man wie eine stink normale nich-void Funktion benutzen kann (s.o).
Bei C89 ist es nicht der Fall, und solche Konstrukte, wie#define foo(a) \ ({ \ ..... \ })
nicht gehen.
Damit kann man auch (dreist) behaupten, dass (bezogen auf jox Aussage über Exoten-Compiler) solche Makros nur von veralteten Compilern nicht geschluckt werden.
Apropos - in Anlehnung an C89 und somit auch an VS .NET müsste man die von mir oben gepostete Makros auf folgende weise umschreiben:
/** * */ #define QUEUE_POP(pQueue, QueueType, Variable) \ do { \ QueueType *pStoredValue = 0; \ pStoredValue = (QueueType*) queue_pop(pQueue); \ Variable = *pStoredValue; \ free(pStoredValue); \ } while(0) /** * */ #define QUEUE_PUSH(pQueue, QueueType, value) \ do { \ QueueType *pValueToBeStored = (QueueType*) malloc(sizeof(QueueType)); \ (*pValueToBeStored) = value; \ queue_push(pQueue, pValueToBeStored); \ } while(0) /** * */ #define QUEUE_TOP(pQueue, QueueType, Variable) \ do { \ QueueType *pStoredValue = 0; \ pStoredValue = (QueueType*) queue_top(pQueue); \ Variable *pStoredValue; \ } while(0)
wobei die Benutzung dieser z.B. bei Schleifen sehr unbequem ist:
Bsp für C99:
// q ist eine pointer auf struct queue while(QUEUE_POP(q, int) != 0) { // mache etwas }
und das selbe mit C98
// q ist eine pointer auf struct queue int i; QUEUE_POP(q, int, i); while(i != 0) { // mache etwas QUEUE_POP(q, int, i); }
c.rackwitz schrieb:
welchen grund hast du, makros fuer sowas zu verwenden?
Das was ich schreibe darf ich leider nicht in cpp schreiben, wo ich um generisch zu bleiben templates benutzen würde. Mit Hilfe der oben angegebenen Makros kann ich auch unter C generisch bleiben.
-
dadrus schrieb:
Dieser Standard erlaubt es unter Anderem Makros zu schreiben, die man wie eine stink normale nich-void Funktion benutzen kann (s.o).
Bei C89 ist es nicht der Fall, und solche Konstrukte, wie#define foo(a) \ ({ \ ..... \ })
nicht gehen.
Damit kann man auch (dreist) behaupten, dass (bezogen auf jox Aussage über Exoten-Compiler) solche Makros nur von veralteten Compilern nicht geschluckt werden.
Ähm, nein, das geht auch durch keinen C99-kompatiblen Compiler.
#define QUEUE_POP(pQueue, QueueType, Variable) \ do { \ QueueType *pStoredValue = 0; \ pStoredValue = (QueueType*) queue_pop(pQueue); \ Variable = *pStoredValue; \ free(pStoredValue); \ } while(0) [...]
wobei die Benutzung dieser z.B. bei Schleifen sehr unbequem ist:
Bsp für C99:
// q ist eine pointer auf struct queue while(QUEUE_POP(q, int) != 0) { // mache etwas }
Nein, das ist kein erlaubtes C99, weil ein compound statement (also irgendwas, was mit { anfängt und mit } wieder aufhört) keine Werte zurückgibt. ({ ... }) ist eine GNU-Erweiterung, mit C hat das nichts zu tun.
[Es gibt in C99 coumpound literals, wo auch { und ( involviert sind, aber die sehen etwas anders aus.]
-
Hm...
Dann habe ich was flasches gehört, bzw. verstanden.
Danke für die Belehrung.
-
dadrus schrieb:
Apropos - in Anlehnung an C89 und somit auch an VS .NET müsste man die von mir oben gepostete Makros auf folgende weise umschreiben:
/** * */ #define QUEUE_POP(pQueue, QueueType, Variable) \ do { \ QueueType *pStoredValue = 0; \ pStoredValue = (QueueType*) queue_pop(pQueue); \ Variable = *pStoredValue; \ free(pStoredValue); \ } while(0) ... ...
...und wozu ist das 'do{...}while(0)' gut ?
-
... damit der Optimierungslauf beim Compiler seine Daseinsberechtigung unter Beweis stellen kann...
----
Hi @net, ich dachte schon, jetzt hätten wir die Lösung, war wohl wieder nix
-
net schrieb:
...und wozu ist das 'do{...}while(0)' gut ?
Das hat schon seinen Sinn. Damit kann man dann das Makro (fast) so behandeln, wie einen Funktionsaufruf,
das Unterbringen in if-Verschachtelungen ist kein Problem mehr.
if(bed1) if(bed2) QUEUE_POP(a,b,c); else something_different();
Wenn man jetzt QUEUE_POP nur in einen Block gepackt hätte, dann würde das else hier dem falschen if zugeordnet werden (beachte das Semikolon).
-
Daniel E. schrieb:
...(beachte das Semikolon).
ach so, ein kleiner trick
naja, ich hab mir sowieso angewöhnt, solche makros nie direkt hinter ein 'if' zu schreiben bzw. wenn's nicht anders geht alles im 'if' in {} einzupacken. gerade wenn man makros für debugausgaben hat, die im release build wech sind, bezieht sich das 'if' auf die übernächste zeile. solche fehler sind lustig: im debug modus geht alles - aber die releaseversion zickt gewaltig rum