Ist snprintf immer null, um den Zielpuffer zu beenden?
Mit anderen Worten, ist dies ausreichend:
char dst[10];
snprintf(dst, sizeof (dst), "blah %s", somestr);
oder musst du das so machen, wenn somestr lang genug ist?
char dst[10];
somestr[sizeof (dst) - 1] = '\0';
snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);
Ich interessiere mich sowohl für das, was der Standard sagt, als auch für das, was eine beliebte libc tun könnte, was kein Standardverhalten ist.
Antworten:
Wie die anderen Antworten ergeben: Es sollte :
Sie müssen also nur darauf achten, dass Sie keinen Puffer mit der Größe Null an ihn übergeben, da er (offensichtlich) keine Null ins "Nirgendwo" schreiben kann.
Doch Vorsicht , dass Microsoft die Bibliothek
nicht hat eine Funktion namenshistorisch nur hatte eine Funktion namenssnprintf
sondern_snprintf
(Anmerkung führende Unterstrich) , die nicht nicht anhängen eine abschließende Null. Hier sind die Dokumente (VS 2012, ~~ VS 2013):http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx
Visual Studio 2015 (VC14) hat anscheinend die konforme
snprintf
Funktion eingeführt, aber die ältere mit dem führenden Unterstrich und dem nicht nullterminierenden Verhalten ist immer noch vorhanden:quelle
_snprintf
dem ein wichtiges Sicherheitsmerkmalsnprintf
stillschweigend entfernt wird und die Zeichenfolge nicht nullterminiert werden kann?!template <size_t size> int _snprintf_s(char (&buffer)[size], size_t count, const char *format [, argument] ...);
und ich sollte auch erwähnen, dass dies nur mit dem Kompilierungsflag / GS (Security Check) passiert. Diese Funktion kennt Größe, Anzahl und Länge.Laut snprintf (3) Manpage.
Also, ja, keine Notwendigkeit zu beenden, wenn Größe> = 1.
quelle
Gemäß dem C-Standard, es sei denn, die Puffergröße ist 0
vsnprintf()
undsnprintf()
null beendet die Ausgabe.Wenn Sie also wissen möchten, wie groß ein zuzuweisender Puffer ist, verwenden Sie eine Größe von Null, und Sie können dann einen Nullzeiger als Ziel verwenden. Beachten Sie, dass ich auf die POSIX-Seiten verlinkt habe, aber diese sagen ausdrücklich, dass es keine Abweichungen zwischen Standard C und POSIX geben soll, wenn sie denselben Grund abdecken:
Seien Sie vorsichtig mit der Microsoft-Version von
vsnprintf()
. Es verhält sich definitiv anders als die Standard-C-Version, wenn nicht genügend Speicherplatz im Puffer vorhanden ist (es gibt -1 zurück, wobei die Standardfunktion die erforderliche Länge zurückgibt). Es ist nicht ganz klar, dass die Microsoft-Version null ihre Ausgabe unter Fehlerbedingungen beendet, während dies bei der Standard-C-Version der Fall ist.Beachten Sie auch die Antworten auf Verwenden Sie die sicheren Funktionen des TR 24731? (siehe MSDN für die Microsoft-Version der
vsprintf_s()
) und Mac-Lösung für die sicheren Alternativen zu unsicheren C-Standardbibliotheksfunktionen?quelle
Einige ältere Versionen von SunOS haben seltsame Dinge mit snprintf gemacht und möglicherweise die Ausgabe nicht durch NUL beendet und Rückgabewerte erhalten, die nicht mit denen aller anderen übereinstimmten, aber alles, was in den letzten 10 Jahren veröffentlicht wurde, hat das getan, was C99 sagt.
quelle
Die Mehrdeutigkeit geht vom C-Standard selbst aus. Sowohl C99 als auch C11 haben eine identische
snprintf
Funktionsbeschreibung. Hier ist die Beschreibung von C99:Einerseits der Satz
sagt, dass
wenn (die
s
Punkte auf ein 3 Zeichen langes Array und)n
3 sind, 2 Zeichen geschrieben werden und die Zeichen jenseits des zweiten verworfen werden ; dann wird das Nullzeichen nach diesen 2 geschrieben (und das Nullzeichen ist das 3. geschriebene Zeichen) .Und das beantwortet meiner Meinung nach die ursprüngliche Frage.
DIE ANTWORT:
Wenn zwischen überlappenden Objekten kopiert wird, ist das Verhalten undefiniert.
Wenn
n
0 ist, wird nichts in die Ausgabe geschrieben,andernfalls wird die Ausgabe IMMER nullterminiert , wenn keine Codierungsfehler aufgetreten sind ( unabhängig davon, ob die Ausgabe in das Ausgabearray passt oder nicht ; wenn nicht, werden einige Zeichen so verworfen, dass die Ausgabe erfolgt Array wird nie überflogen),
andernfalls (wenn Codierungsfehler auftreten) kann die Ausgabe nicht nullterminiert bleiben .
Auf der anderen Seite
Der letzte Satz
gibt Mehrdeutigkeit (oder mein Englisch ist nicht gut genug). Ich kann diesen Satz auf mindestens zwei Arten interpretieren:
1. Die Ausgabe wird genau dann nullterminiert , wenn der zurückgegebene Wert nicht negativ und kleiner als ist
n
(was bedeutet, dass wenn der zurückgegebene Wert nicht kleiner als istn
, dh die Ausgabe (einschließlich der) Nullzeichen beenden) passt nicht in das Array, dann ist die Ausgabe nicht nullterminiert ).2. Die Ausgabe ist genau dann abgeschlossen (es wurden keine Zeichen verworfen), wenn der zurückgegebene Wert nicht negativ und kleiner als ist
n
.Ich glaube, dass die obige Interpretation 1 DER ANTWORT widerspricht, Missverständnisse und langwierige Diskussionen hervorruft. Aus diesem Grund muss der letzte Satz, der die
snprintf
Funktion beschreibt, geändert werden, um Unklarheiten zu beseitigen (was Anlass gibt, einen Vorschlag für den C-Sprachstandard zu schreiben).Das Beispiel für eine nicht mehrdeutige Formulierung, von der ich glaube, kann http://en.cppreference.com/w/c/io/fprintf (siehe
4)
) entnommen werden , danke an @ "Martin Ba" für den Link.Siehe auch die Frage " snprintf: Gibt es C-Standardvorschläge / Pläne zur Änderung der Beschreibung dieser Funktion? ".
quelle