ps Ich weiß, dass ich die Länge der Ganzzahl auch über das Protokoll erhalten kann, aber auf diese Weise scheint es schöner zu sein.
um die Länge zu ermitteln stackoverflow.com/questions/1068849/…
– Keith Nicholas
16. März 2015 um 21:26 Uhr
Mögliches Duplikat von Bestimmen der sprintf-Puffergröße – was ist der Standard?
– Ciro Santilli OurBigBook.com
19. März 2017 um 7:05 Uhr
meinaut
Da C eine einfache Sprache ist, gibt es keine “wegwerfbaren Puffer” – die gesamte Speicherverwaltung liegt auf den Schultern des Programmierers (es gibt GNU C-Compiler-Erweiterungen dafür, aber sie sind kein Standard).
kann vorher nicht wissen, wie viele Zeichen lang die Ganzzahl ist.
Es gibt viel einfachere Lösung für Ihr Problem. snprintf weiß!
Auf C99-kompatiblen Plattformen rufen Sie snprintf mit NULL als erstem Argument auf:
Verwenden Sie in älteren Visual Studio-Versionen (mit nicht C99-kompatibler CRT). _scprintf Anstatt von snprintf(NULL, ...) Anruf.
Unterstützt Visual Studio (zumindest in neueren Versionen) eine Funktion namens nicht _snprintf das ist ähnlich dem Standard snprintf?
– Keith Thompson
16. März 2015 um 21:30 Uhr
@KeithThompson: MSDN überprüft, es scheint, dass sie das ab VS2013 behoben haben. Danke für den Hinweis, ich habe meine Antwort aktualisiert
– myaut
16. März 2015 um 21:33 Uhr
Notiz: snprintf() kann auch -1 zurückgeben und hat in Kurvensituationen Probleme als der Maximalwert von size_t und int sind selten gleich. Möglicherweise gibt es ein Problem mit der 2 snprintf() Sollte die locale Wechsel zwischen ihnen und der 2. `Ausgang ist länger.
– chux – Wiedereinsetzung von Monica
16. März 2015 um 22:03 Uhr
@chux: Natürlich ist mein Code generisch und sollte Fehlerprüfungen enthalten, einschließlich INT_MAX und -1und ssize_t ist kein Anliegen von snprintf(). Apropos Gebietsschema ändern – wir erhalten eine nicht-NULL-terminierte Zeichenfolge (also sollten wir die 2 snprintf() auch), aber zumindest wird es keinen Pufferüberlauf verursachen (zumindest direkt). AFAIK, es ist schwierig, das Gebietsschema extern zu ändern.
– myaut
16. März 2015 um 22:17 Uhr
Brian Campell
Du kannst anrufen int len = snprintf(NULL, 0, "{data:%d}", 12312) um zu testen, wie viel Platz Sie benötigen.
snprintf wird höchstens gedruckt size Zeichen, wo size ist das zweite Argument und gibt zurück, wie viele Zeichen nötig gewesen wären, um das Ganze zu drucken, ohne das Ende zu zählen '\0'. Da Sie 0 übergeben, wird tatsächlich nichts ausgeschrieben (und somit jede Nullzeiger-Ausnahme vermieden, die beim Versuch einer Dereferenzierung auftreten würde NULL), aber es wird immer noch die Länge zurückgegeben, die für die gesamte Ausgabe erforderlich ist, die Sie zum Zuweisen Ihres Puffers verwenden können.
An diesem Punkt können Sie Ihren Puffer zuweisen und drucken, wobei Sie daran denken, einen weiteren für den Nachlauf einzufügen '\0':
Vielen Dank. Genau das, was ich brauchte. Komisch, dass das nicht in der Kurzanleitung stand. Ich denke, darauf kommt es bei der Erfahrung an. Grüße
– weißt du
16. März 2015 um 21:33 Uhr
Sie sollten auch erwähnen, dass bei Verwendung eines NULL-Puffers die String-Beendigung nicht gezählt wird. de.cppreference.com/w/c/io/fprintf
– weißt du
16. März 2015 um 21:48 Uhr
@Aldi Danke für den Hinweis, aktualisiert, um diese Klarstellung aufzunehmen.
– Brian Campell
16. März 2015 um 21:55 Uhr
Um nur die Länge zu erhalten, können Sie schreiben:
int length = snprintf(NULL, 0, "{data:%d}", 12312);
Beachten Sie, dass der Rückgabetyp ist int. Es kann zurückkehren -1 im Falle eines Fehlers. Stellen Sie sicher, dass Ihre Eingabedaten keine langen Zeichenfolgen enthalten, die dazu führen könnten, dass die Gesamtlänge überschritten wird INT_MAX !
Sie können die maximale Größe (10 unter der Annahme von 32 Bit) + 8 – also 18 leicht berechnen
– Ed heilen
16. März 2015 um 21:29 Uhr
@EdHeal meine Lösung macht keine Annahmen über die Größen von Typen. Ich bin mir sicher, dass es eine Menge Code gibt, der genau aus diesem Grund kaputt gegangen ist, als er für ein 64-Bit-Ziel neu kompiliert wurde.
– MM
16. März 2015 um 21:31 Uhr
@mattMcNadd – Für die Geschwindigkeit besteht die Lösung nur darin, eine Konstante zu haben – dies ist ein Fall, in dem der Pro-Prozessor praktisch ist.
– Ed heilen
16. März 2015 um 21:34 Uhr
Meine Antworten konzentrieren sich auf Korrektheit über Geschwindigkeit 🙂 Mikrooptimierung kann später kommen. YMMV, nehme ich an.
– MM
16. März 2015 um 21:34 Uhr
@chux – Brunel ist einer meiner Helden. Damals haben sie das Zeug überarbeitet. Aber die Brücken usw. sind noch in Gebrauch. Aber die Forth-Straßenbrücke wird ersetzt, aber die Forth-Eisenbahnbrücke bekommt gerade einen neuen Anstrich, und bei der Clifton-Brücke könnten die Linien in der Mitte der Straße dieses Jahr neu gestrichen werden
– Ed heilen
16. März 2015 um 22:13 Uhr
Wenn Sie die Leistung überprüfen, wird die Ausführung von snprintf ohne Ausgabepuffer ungefähr so lange dauern wie ein vollständiger Aufruf.
Daher empfehle ich Ihnen, für alle Fälle einen kleineren Puffer zu verwenden und ihn nur ein zweites Mal aufzurufen, wenn die zurückgegebene Größe die Puffergröße überschreitet.
Dies verwendet C++ std::string aber ich denke, du kannst es an deine Bedürfnisse anpassen.
std::string format(const char* format, ...) {
va_list args;
va_start(args, format);
char smallBuffer[1024];
int size = vsnprintf(smallBuffer, sizeof smallBuffer, format, args);
va_end(args);
if (size < sizeof smallBuffer)
return std::string(smallBuffer);
char buffer[size + 1]; /* maybe malloc if it's too big */
va_start(args, format);
vsnprintf(buffer, sizeof buffer, format, args);
va_end(args);
return std::string(buffer);
}
Dieser Code läuft 2x schneller für Strings unter 1k im Vergleich zu den längeren.
Der Aufruf von snprintf(nullptr, 0, …) gibt zwar die Größe zurück, hat aber Leistungseinbußen, da IO_str_overflow aufgerufen wird und das langsam ist.
Wenn Ihnen die Leistung wichtig ist, können Sie einen Dummy-Puffer vorab zuweisen und seinen Zeiger und seine Größe an ::snprintf übergeben. es wird um ein Vielfaches schneller sein als die nullptr-Version.
template<typename ...Args>
size_t get_len(const char* format, Args ...args) {
static char dummy[4096]; // you can change the default size
return ::snprintf(dummy, 4096, format, args...) + 1; // +1 for \0
}
Die Frage ist mit c gekennzeichnet; Warum haben Sie mit C++-Code geantwortet?
– ad absurdum
10. Januar 2020 um 5:25 Uhr
@exnihilo ah, sorry, ich habe das Tag verpasst
– DAG
10. Januar 2020 um 8:57 Uhr
neunzigfan
Printf unterstützt den %n-Formatparameter, was bedeutet „Position von %n in der Ausgabezeichenfolge in den int-Wert schreiben, auf den der x-Parameter zeigt), also:
int x;snprintf(NULL, 0, "Message: %s%n", "Error!",&x);
Sollte funktionieren!
Die Frage ist mit c gekennzeichnet; Warum haben Sie mit C++-Code geantwortet?
– ad absurdum
10. Januar 2020 um 5:25 Uhr
@exnihilo ah, sorry, ich habe das Tag verpasst
– DAG
10. Januar 2020 um 8:57 Uhr
Dolda2000
Dies ist nicht unbedingt eine Antwort auf Ihre Frage, aber Sie können es dennoch hilfreich finden. Es ist nicht portabel, aber wenn Sie es auf glibc ausführen, können Sie es einfach verwenden asprintf() stattdessen, was die Speicherzuweisung für Sie übernimmt.
13694400cookie-checkWie berechnet man die Länge der Ausgabe, die sprintf generiert?yes
um die Länge zu ermitteln stackoverflow.com/questions/1068849/…
– Keith Nicholas
16. März 2015 um 21:26 Uhr
Mögliches Duplikat von Bestimmen der sprintf-Puffergröße – was ist der Standard?
– Ciro Santilli OurBigBook.com
19. März 2017 um 7:05 Uhr