Ich habe eine Funktion, die eine Zeichenfolge akzeptiert, das heißt:
void log_out(char *);
Wenn ich es aufrufe, muss ich eine formatierte Zeichenfolge im laufenden Betrieb erstellen, wie:
int i = 1;
log_out("some text %d", i);
Wie mache ich das in ANSI C?
Nur, da sprintf()
ein int zurückgegeben wird, bedeutet dies, dass ich mindestens 3 Befehle schreiben muss, wie:
char *s;
sprintf(s, "%d\t%d", ix, iy);
log_out(s);
Wie kann man das verkürzen?
Antworten:
Verwenden Sie sprintf .
Parameter:
Beispiel:
quelle
Wenn Sie ein POSIX-2008-kompatibles System haben (jedes moderne Linux), können Sie die sichere und bequeme
asprintf()
Funktion verwenden: Es verfügt übermalloc()
genügend Speicherplatz, Sie müssen sich keine Gedanken über die maximale Zeichenfolgengröße machen. Verwenden Sie es so:Dies ist der minimale Aufwand, den Sie benötigen, um die Zeichenfolge auf sichere Weise zu erstellen. Der
sprintf()
Code, den Sie in der Frage angegeben haben, ist zutiefst fehlerhaft:Hinter dem Zeiger befindet sich kein zugewiesener Speicher. Sie schreiben die Zeichenfolge an eine zufällige Stelle im Speicher!
Auch wenn du geschrieben hast
Sie wären in großen Schwierigkeiten, weil Sie nicht wissen, welche Nummer Sie in die Klammern setzen sollen.
Selbst wenn Sie die "sichere" Variante verwendet
snprintf()
hätten, besteht die Gefahr, dass Ihre Zeichenfolgen abgeschnitten werden. Beim Schreiben in eine Protokolldatei ist dies ein relativ geringes Problem, es kann jedoch genau die Informationen abgeschnitten werden, die nützlich gewesen wären. Außerdem wird das nachfolgende Endzeilenzeichen abgeschnitten und die nächste Protokollzeile an das Ende Ihrer erfolglos geschriebenen Zeile geklebt.Wenn Sie versuchen, in allen Fällen eine Kombination aus
malloc()
undsnprintf()
korrektes Verhalten zu erzeugen, erhalten Sie ungefähr doppelt so viel Code wie ich angegeben habeasprintf()
, und programmieren die Funktionalität von im Grunde neuasprintf()
.Wenn Sie auf der Bereitstellung eine Hülle aus suchen ,
log_out()
dass kann eine Take -printf()
Stil Parameterliste selbst, können Sie die Variante verwenden ,vasprintf()
die eine nimmtva_list
als Argument. Hier ist eine absolut sichere Implementierung eines solchen Wrappers:quelle
asprintf()
weder Teil von Standard C 2011 noch Teil von POSIX ist, auch nicht von POSIX 2008 oder 2013. Es ist Teil von TR 27431-2: siehe Verwenden Sie die sicheren FunktionenFür mich klingt es so, als ob Sie in der Lage sein möchten, eine Zeichenfolge, die mit printf-Format erstellt wurde, einfach an die Funktion zu übergeben, die Sie bereits haben und die eine einfache Zeichenfolge benötigt. Sie können eine Wrapper-Funktion mithilfe von Funktionen erstellen
stdarg.h
undvsnprintf()
(die je nach Compiler / Plattform möglicherweise nicht sofort verfügbar sind):Für Plattformen, die keine gute Implementierung (oder Implementierung) der
snprintf()
Routinenfamilie bieten , habe ich erfolgreich eine nahezu öffentliche Domainsnprintf()
von Holger Weiss verwendet .quelle
Wenn Sie den Code dazu haben
log_out()
, schreiben Sie ihn neu. Höchstwahrscheinlich können Sie Folgendes tun:Wenn zusätzliche Protokollierungsinformationen erforderlich sind, können diese vor oder nach der angezeigten Nachricht gedruckt werden. Dies spart Speicherzuordnung und zweifelhafte Puffergrößen und so weiter und so fort. Sie müssen wahrscheinlich
logfp
auf Null initialisieren (Nullzeiger) und prüfen, ob es Null ist, und die Protokolldatei entsprechend öffnen - aber der Code in der vorhandenenlog_out()
sollte sich trotzdem darum kümmern .Der Vorteil dieser Lösung ist, dass Sie sie einfach so nennen können, als wäre sie eine Variante von
printf()
; in der Tat ist es eine kleine Variante aufprintf()
.Wenn Sie nicht über den Code verfügen
log_out()
, prüfen Sie, ob Sie ihn durch eine Variante wie die oben beschriebene ersetzen können. Ob Sie denselben Namen verwenden können, hängt von Ihrem Anwendungsframework und der endgültigen Quelle der aktuellenlog_out()
Funktion ab. Wenn es sich in derselben Objektdatei befindet wie eine andere unverzichtbare Funktion, müssten Sie einen neuen Namen verwenden. Wenn Sie nicht herausfinden können, wie Sie es genau replizieren können, müssen Sie eine Variante verwenden, wie sie in anderen Antworten angegeben ist, die eine angemessene Menge an Speicher zuweist.Natürlich rufen Sie jetzt das
log_out_wrapper()
anstelle von auflog_out()
- aber die Speicherzuweisung usw. erfolgt einmal. Ich behalte mir das Recht vor, Speicherplatz um ein unnötiges Byte zu überschreiben. Ich habe nicht überprüft, ob die von zurückgegebene Längevsnprintf()
die abschließende Null enthält oder nicht.quelle
Verwenden Sie kein Sprintf.
Es wird Ihren String-Buffer überlaufen lassen und Ihr Programm zum Absturz bringen.
Verwenden Sie immer snprintf
quelle
Ich habe das nicht getan, also werde ich nur auf die richtige Antwort zeigen.
C enthält Bestimmungen für Funktionen, die mithilfe des
<stdarg.h>
Headers eine nicht angegebene Anzahl von Operanden annehmen . Sie können Ihre Funktion als definierenvoid log_out(const char *fmt, ...);
und dasva_list
Innere der Funktion abrufen. Dann können Sie Speicher zuweisen undvsprintf()
mit dem zugewiesenen Speicher, Format und aufrufenva_list
.Alternativ können Sie damit eine analoge Funktion schreiben
sprintf()
, die Speicher zuweist und die formatierte Zeichenfolge zurückgibt und sie mehr oder weniger wie oben generiert. Es wäre ein Speicherverlust, aber wenn Sie sich nur abmelden, spielt dies möglicherweise keine Rolle.quelle
http://www.gnu.org/software/hello/manual/libc/Variable-Arguments-Output.html enthält das folgende Beispiel zum Drucken auf stderr. Sie können es ändern, um stattdessen Ihre Protokollfunktion zu verwenden:
Anstelle von vfprintf müssen Sie vsprintf verwenden, wo Sie einen geeigneten Puffer zum Drucken bereitstellen müssen.
quelle