Funktion mit variabler Argumentenliste à la printf
-
Hi,
kennt jemand Details der Implementierung der printf-Funktion? So etwas ähnliches brauche ich nämlich.
Möchte eine Funktion
void log(int type, CString msg, ...);
schreiben, die beliebig viele Argumente mit beliebigen Datentypen akzeptiert.
Innerhalb der Funktion soll dann per CString::Format() der CString msg zusammengesetzt werden.D.h., der Aufruf soll beispielsweise so aussehen:
int i=0; log(type_x, "integer = %d", i)
und innerhalb der Funktion log geschieht dann das:
CString cs; cs.Format(msg, i);
Im Grunde müsste ich nur die komplette Argumentenliste hinter msg an die Funktion cs.Format() weitergeben, aber wie macht man das?
Gruß, Thomas
-
Dort, wo's CString gibt, gibt's afaik auch variable Argumentlisten im Sprachumfang.
Was ANSI C angeht: Am einfachsten geht das mit va_list.
Das Stichwort ist (seit ISO C): variadic functionsEDIT:
Du könntest natürlich auch einfach pfuschen, wenn du einen guten Preprozessor hast:#define log(type, msg, ...) sprintf(msg, __VA_ARGS__)
(man merkt, dass ich nicht verstanden habe, wozu type gut ist...)
-
Ja, mit va_list hab ich schon experimentiert.
Hier hab ich was gefunden, um ganze Argumentlisten zu übergeben: http://www.codeproject.com/Purgatory/va_pass.asp
Funktioniert aber nur befriedigend, manchmal bekomme ich unerklärliche Exceptions.log() ist eine Methode einer Klasse Logfile, das Typargument dient dazu, verschiedene Meldungstypen zu unterscheiden. Ist aber für mein Problem eher irrelevant.
-
So sieht meine log Funktion aus (gekürzt):
void log_append(struct log *log, enum log_level level, const char *text, ...) { FILE *logfile; va_list va; logfile = fopen(log->filename, "a+"); va_start(va, text); vfprintf(logfile, text, va); fprintf(logfile, "\n"); va_end(va); fflush(logfile); fclose(logfile); }
aufrufen dann halt mit log_append(.., .., "Test %d", 2);
Edit: Hoppla .. cpp tags vergessen.
-
Bei den klassischen printf()-Funktionen gibt es überall eine Variante mit v*printf(), die anstelle der variablen Argumente einen vorbereiteten va_list entgegennehmen. Ob's das auch für CString (meinst du damit die MFC-Klasse?) gibt, weiß ich allerdings nicht - notfalls nimmst du vsprintf() und kopierst dessen Ausgabe dann in den String.
-
Heureka! Über den Umweg über wvsprintf() gehts tatsächlich.
Der wesentliche Code sieht jetzt so aus:
void log(type t, CString message, ...) { ... wchar_t c[1000]; va_list varlist; va_start(varlist, message); wvsprintf(c, message, varlist); va_end(varlist); f.WriteString(CString(c) + L"\n"); ... }
Da muss ich wahrscheinlich nur beachten, dass ich die Arraygrenzen nicht verletze. Ja, ich benutze CString aus den MFC.
Vielen Dank.
-
Thomas++ schrieb:
Hier hab ich was gefunden, um ganze Argumentlisten zu übergeben: http://www.codeproject.com/Purgatory/va_pass.asp
Funktioniert aber nur befriedigend, manchmal bekomme ich unerklärliche Exceptions.Ist auch kein Wunder. Der Code ist bestenfalls obskur. Spätestens das hier:
try{//to avoid access violation
...und dass man wenn es zuverlässig funktionieren würde keine access violation befürchten müsste brauche ich wohl nicht zu erwähnen