Ich bin unglücklich genug, mit VS 2010 für ein Projekt stecken zu bleiben, und habe festgestellt, dass der folgende Code immer noch nicht mit dem nicht standardkonformen Compiler erstellt wird:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
char buffer[512];
snprintf(buffer, sizeof(buffer), "SomeString");
return 0;
}
(Kompilierung schlägt fehl mit dem Fehler: C3861: ‘snprintf’: Identifier not found)
Ich erinnere mich, dass dies vor langer Zeit bei VS 2005 der Fall war, und ich bin schockiert, dass es immer noch nicht behoben wurde.
Weiß jemand, ob Microsoft irgendwelche Pläne hat, seine Standard-C-Bibliotheken in das Jahr 2010 zu verschieben?
… oder Sie können einfach “#define snprintf _snprintf” tun
– Fernando González Sánchez
25. Februar 2015 um 1:16 Uhr
…könnten Sie, aber leider ist _snprintf() nicht dasselbe wie snprintf(), da es keine Nullterminierung garantiert.
– Andy Krouwel
16. Oktober 2015 um 8:46 Uhr
Ok, also müssen Sie es auf Null setzen, bevor Sie _snprintf() verwenden. Auch da stimme ich dir zu. Unter MSVC zu entwickeln ist schrecklich. Die Fehler sind auch verdammt verwirrend.
– Eule
17. August 2016 um 13:37 Uhr
Valentin Milea
Kurzgeschichte: Microsoft hat snprintf endlich in Visual Studio 2015 implementiert. In früheren Versionen können Sie es wie folgt simulieren.
Lange Version:
Hier ist das erwartete Verhalten für snprintf:
int snprintf( char* buffer, std::size_t buf_size, const char* format, ... );
Schreibt höchstens buf_size - 1 Zeichen in einen Puffer. Die resultierende Zeichenfolge wird mit einem Nullzeichen abgeschlossen, es sei denn buf_size ist Null. Wenn buf_size Null ist, wird nichts geschrieben und buffer kann ein Nullzeiger sein. Der Rückgabewert ist die Anzahl der Zeichen, die unter der Annahme von unbegrenzt geschrieben worden wären buf_sizewobei das abschließende Nullzeichen nicht mitgezählt wird.
Versionen vor Visual Studio 2015 hatten keine konforme Implementierung. Es gibt stattdessen nicht standardmäßige Erweiterungen wie z _snprintf() (der bei Überlauf keinen Nullterminator schreibt) und _snprintf_s() (was eine Null-Terminierung erzwingen kann, aber bei Überlauf -1 anstelle der Anzahl der Zeichen zurückgibt, die geschrieben worden wären).
Vorgeschlagener Fallback für VS 2005 und höher:
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf c99_snprintf
#define vsnprintf c99_vsnprintf
__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
{
int count = -1;
if (size != 0)
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
if (count == -1)
count = _vscprintf(format, ap);
return count;
}
__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = c99_vsnprintf(outBuf, size, format, ap);
va_end(ap);
return count;
}
#endif
Dadurch wird die Zeichenfolge nicht immer mit einer 0 abgeschlossen, die bei einem Überlauf erforderlich ist. Das zweite if in c99_vsnprintf muss sein: if (count == -1) { if (size > 0) str[size-1] = 0; count = _vscprintf (Format, ap); }
– Lothar
11. Februar 2014 um 2:09 Uhr
@Lothar: Der Puffer ist immer nullterminiert. Laut MSDN: “Wenn das Abschneiden von Zeichenfolgen durch Übergeben von _TRUNCATE aktiviert ist, kopieren diese Funktionen nur so viel von der Zeichenfolge, wie hineinpasst, wobei der Zielpuffer nullterminiert bleibt und erfolgreich zurückgegeben wird”.
– Valentin Milea
12. Februar 2014 um 9:18 Uhr
Stand Juni 2014 gibt es noch immer keine “vollständige” C99-Unterstützung in Visual Studio, selbst mit Update 2. Dieser Blog gibt den C99-Supportbrief für MSVC 2013. Da die Funktionen der snprintf()-Familie jetzt Teil des C++11-Standards sind, bleibt MSVC in der C++11-Implementierung hinter clang und gcc zurück!
Mikael Lepistö: Wirklich? Für mich funktioniert _snprintf nur, wenn ich _CRT_SECURE_NO_WARNINGS aktiviere. Diese Problemumgehung funktioniert gut ohne diesen Schritt.
Siehe andere Antworten unten für eine Problemumgehung.
Es ist jedoch keine gute Problemumgehung … da es Unterschiede im Verhalten von snprintf und _snprintf gibt. _snprintf verarbeitet das Null-Terminator verzögert, wenn es um unzureichenden Pufferspeicher geht.
– Andreas
26. Mai 2010 um 18:37 Uhr
@DeadMG – falsch. cl.exe unterstützt die Option /Tc, die den Compiler anweist, eine Datei als C-Code zu kompilieren. Darüber hinaus wird MSVC mit einer Version von Standard-C-Bibliotheken ausgeliefert.
– Andreas
26. Mai 2010 um 20:04 Uhr
@DeadMG – es unterstützt jedoch den C90-Standard sowie einige Teile von C99, was es zu einem C-Compiler macht.
– Andreas
27. Mai 2010 um 14:26 Uhr
Nur wenn Sie zwischen 1990 und 1999 leben.
– Welpe
27. Mai 2010 um 17:41 Uhr
-1, Microsofts _snprintf ist eine unsichere Funktion, die sich anders verhält snprintf (es fügt nicht unbedingt ein Null-Terminator hinzu), daher ist der in dieser Antwort gegebene Rat irreführend und gefährlich.
– zwischenjay
4. Juni 2013 um 9:31 Uhr
Wenn Sie den Rückgabewert nicht benötigen, können Sie snprintf auch einfach als _snprintf_s definieren
#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
Ich glaube, das Windows-Äquivalent ist sprintf_s
Ein weiterer sicherer Ersatz von snprintf() und vsnprintf() wird von ffmpeg bereitgestellt. Sie können die auschecken Quelle hier (empfohlen).
Ich habe den Code von @Valentin Milea ausprobiert, aber ich habe Zugriffsverletzungsfehler. Das einzige, was für mich funktioniert hat, war die Implementierung von Insane Coding: http://asprintf.insanecoding.org/
Insbesondere habe ich mit VC++2008-Legacy-Code gearbeitet. Aus der Implementierung von Insane Coding (kann über den obigen Link heruntergeladen werden) habe ich drei Dateien verwendet: asprintf.c, asprintf.h und vasprintf-msvc.c. Andere Dateien waren für andere Versionen von MSVC.
[EDIT] Der Vollständigkeit halber sind ihre Inhalte wie folgt:
… oder Sie können einfach “#define snprintf _snprintf” tun
– Fernando González Sánchez
25. Februar 2015 um 1:16 Uhr
…könnten Sie, aber leider ist _snprintf() nicht dasselbe wie snprintf(), da es keine Nullterminierung garantiert.
– Andy Krouwel
16. Oktober 2015 um 8:46 Uhr
Ok, also müssen Sie es auf Null setzen, bevor Sie _snprintf() verwenden. Auch da stimme ich dir zu. Unter MSVC zu entwickeln ist schrecklich. Die Fehler sind auch verdammt verwirrend.
– Eule
17. August 2016 um 13:37 Uhr