Problem mit #define (mal wieder)
-
Hi!
Ich hatte dieses Problem damals bereits schon einmal angesprochen und dachte auf eine Lösung gekommen zu sein.Folgende Problemstellung:
Ich möchte eine DEBUG-Funktion schreiben, die einen String in eine Datei schreibt. Diese Debug-Funktion soll als Parameter ähnlich wie printf arbeiten.Über ein #define soll das ganze gesteuert werden. Wenn diese Definition existiert, soll die Debug-Funktion aufgerufen werden, ansonsten soll der Code so sein, als würde ich niemals eine Funktion aufrufen.
Das ganze sieht etwa so aus bislang:
H-Datei:
#define _DEBUG_ACTIVE inline void NoLog(const char *msg, ...) { }; #ifdef _DEBUG_ACTIVE void Log(const char *msg, ...); # define Debug Log #else # define Debug NoLog #endif
CPP-Datei:
//... #ifdef _DEBUG_ACTIVE void Log(const char *msg, ...) { //... actionen durchführen ... } #endif int main(int argc, char* argv[]) { Debug("Hallo %s Test", "dies ist ein"); return 0; }
Eins vorweg: Es funktioniert, wie es soll. wenn _DEBUG_ACTIVE definiert ist wird der String an die Datei angehangen, ansonsten passiert nichts beim Aufruf von Debug.
Mein Problem nun sind eigentlich nur ein paar Feinheiten:
Jedesmal folgenden Code schreiben zu müssen für jedes Debug ist mir zu umständlich (und unübersichtlich):int main(int argc, char* argv[]) { # ifdef _DEBUG_ACTIVE Log("Hallo %s Test", "dies ist ein"); # endif return 0; }
Das Problem ist, dass in der fertigen EXE die NoLog Funktion immernoch aufgerufen wird, auch wenn sie leer ist.
So sieht die EXE Datei an der Stelle aus, wenn _DEBUG_ACTIVE nicht definiert ist.
; ... PUSH Engine.00406030 "Dies ist ein Test" CALL Engine.NoLog ADD ESP,4 ; ... XOR EAX, EAX RETN 10 NoLog: RETN
Mit währe ehrlich gesagt in der Endgültigen Version sowas lieber:
; ... ; ... XOR EAX, EAX RETN 10
Andererseits möchte ich auch nicht auf die Funktionsweise alá printf verzichten. Was meint: Log("fps: %i", FramesPerSecond) sollte immernoch gehen. Ohne dem währe es kein Problem.
#define Debug(Message,...) Log(Message,...)
geht leider nicht mit dem Compiler von Visual C++ 6.0.
Hoffe es gibt eine Lösung zu dem Problem.
Bye
~Eich
-
_ProfEich schrieb:
#define _DEBUG_ACTIVE inline void NoLog(const char *msg, ...) { }; #ifdef _DEBUG_ACTIVE void Log(const char *msg, ...); # define Debug Log #else # define Debug NoLog #endif
statt der nichtstuenden Inline-Funktion, könntest du das so definieren:
#define Debug do {} while(0)
-
etwas in der art vielleicht ?
#define _DEBUG_ACTIVE #ifdef _DEBUG_ACTIVE void Log(const char *msg, ...); #else #define Log if(true);else #endif
es wundert mich aber, dass da noch etwas von der funktion übrig bleibt. hast du alle optimierungen eingeschaltet?
-
Hi!
Also die Version mit dem do{}while(0) funktioniert so nicht. Aber ich denke du hattest dabei denselben Hintergedanken wie camper.
Und tatsächlich. Klingt auch logisch.
Ich habe nun den Code so:#ifdef _DEBUG_ACTIVE # define Debug Log #else # define Debug #endif
So übersetzt er das ja etwa so in den Code um das nochmal nachzuvollziehen was die Idee von euch nun brachte
int main(int argc, char*argv[]) { ("Hallo %s Test", "dies ist ein"); }
und das wird vom Compiler natürlich ignoriert
Vielen Dank für die Hilfe, auf solche (eigentlich ja simplen) Lösungen währe ich bestimmt nicht gekommen ^^"
Optimierungen hatte ich bei der alten Version alle an. Ich hatte sogar mal die Option "Minimize Size" extra dafür anstelle von "Maximum speed" ausgewählt.
Danke
~ Eich
-
_ProfEich schrieb:
Also die Version mit dem do{}while(0) funktioniert so nicht.
stimmt, es hätte so aussehen sollen:
#define debug(format, args...) do {} while(0)
Für den gcc ist das ein bischen schöner, weils keine "no effect"-Warnungen gibt.
Dafür sind Makros mit beliebigen Argumenten aber auch nur eine gcc-Erweiterung
-
Da er aber den MSC 6 benutzt, wird ihm das nicht viel nützen.
@_ProfEich
Lass das mit der inline Funktion ruhig so. Ich würde mir darüber keine Gedanken machen. Und kann camper's Frage eigentlich nur noch mal wiederholen - hast du alle Optimierungen beim Release Build eingeschaltet? Ein aktueller Compiler optimiert den Funktionsaufruf weg, wozu er MSC 6 zugegeben aber nicht mehr gehört.
-
groovemaster schrieb:
Da er aber den MSC 6 benutzt, wird ihm das nicht viel nützen.
@_ProfEich
Lass das mit der inline Funktion ruhig so. Ich würde mir darüber keine Gedanken machen. Und kann camper's Frage eigentlich nur noch mal wiederholen - hast du alle Optimierungen beim Release Build eingeschaltet? Ein aktueller Compiler optimiert den Funktionsaufruf weg, wozu er MSC 6 zugegeben aber nicht mehr gehört.Kommt natürlich auf die Parameter an! Wenn du so etwas wie SDL_GetError() als Parameter angeben würdest dann weiß der Compiler nicht ob diese Funktion Seiteneffekte hat oder nicht. Also findet der Aufruf (von SDL_GetError()) statt.
Meiner Meinung nach führen um das was du tuen willst, im Standard C++, keine Wege an doppelten Klammern vorbei.
-
Irgendwer schrieb:
groovemaster schrieb:
Da er aber den MSC 6 benutzt, wird ihm das nicht viel nützen.
@_ProfEich
Lass das mit der inline Funktion ruhig so. Ich würde mir darüber keine Gedanken machen. Und kann camper's Frage eigentlich nur noch mal wiederholen - hast du alle Optimierungen beim Release Build eingeschaltet? Ein aktueller Compiler optimiert den Funktionsaufruf weg, wozu er MSC 6 zugegeben aber nicht mehr gehört.Kommt natürlich auf die Parameter an! Wenn du so etwas wie SDL_GetError() als Parameter angeben würdest dann weiß der Compiler nicht ob diese Funktion Seiteneffekte hat oder nicht. Also findet der Aufruf (von SDL_GetError()) statt.
Meiner Meinung nach führen um das was du tuen willst, im Standard C++, keine Wege an doppelten Klammern vorbei.
das wird mit meinem macro sehr wohl vermieden (schliesslich wird der else zweig nie ausgeführt werden). im schlimmsten falle befindet sich an der stelle im code ein sprung, aber ich glaube, selbst vc6 is nicht so grottig beim optimieren.
-
Irgendwer schrieb:
Kommt natürlich auf die Parameter an! Wenn du so etwas wie SDL_GetError() als Parameter angeben würdest dann weiß der Compiler nicht ob diese Funktion Seiteneffekte hat oder nicht. Also findet der Aufruf (von SDL_GetError()) statt.
Ja, aber der Aufruf von SDL_GetError und NoLog sind immer noch zwei verschiedene Dinge. Selbst wenn SDL_GetError aufgerufen wird, heisst das noch lange nicht, dass die NoLog Funktion auch aufgerufen wird, oder gar im Speicher existiert.