Sono abbastanza sfortunato da rimanere bloccato con VS 2010 per un progetto e ho notato che il seguente codice non viene ancora creato utilizzando il compilatore non conforms agli standard:
#include #include int main (void) { char buffer[512]; snprintf(buffer, sizeof(buffer), "SomeString"); return 0; }
(fallisce la compilazione con l’errore: C3861: ‘snprintf’: identificatore non trovato)
Ricordo che questo è il caso di VS 2005 e sono scioccato nel vedere che non è stato ancora risolto.
Qualcuno sa se Microsoft ha in programma di spostare le sue librerie C standard nell’anno 2010?
Breve storia: Microsoft ha finalmente implementato snprintf in Visual Studio 2015. Nelle versioni precedenti è ansible simularlo come di seguito.
Versione lunga:
Ecco il comportamento previsto per snprintf:
int snprintf( char* buffer, std::size_t buf_size, const char* format, ... );
Scrive al massimo
buf_size - 1
carattere in un buffer. La stringa di caratteri risultante verrà terminata con un carattere null, a meno chebuf_size
sia zero. Sebuf_size
è zero, non viene scritto nulla e ilbuffer
può essere un puntatore nullo. Il valore restituito è il numero di caratteri che sarebbero stati scritti assumendo unbuf_size
illimitato dibuf_size
, senza contare il carattere null terminante.
Le versioni precedenti a Visual Studio 2015 non disponevano di un’implementazione conforms. Esistono invece estensioni non standard come _snprintf()
(che non scrive null-terminator su overflow) e _snprintf_s()
(che può imporre la terminazione nulla, ma restituisce -1 in overflow invece del numero di caratteri che verrebbe sono stati scritti).
Fallimento suggerito per VS 2005 e versioni successive:
#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
snprintf
non fa parte di C89. È standard solo nel C99. Microsoft non ha piani per supportare C99 .
(Ma è anche standard in C ++ 0x …!)
Vedere altre risposte di seguito per una soluzione alternativa.
Se non hai bisogno del valore di ritorno, puoi anche definire snprintf come _snprintf_s
#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
Credo che l’equivalente di Windows sia sprintf_s
Un’altra sostituzione sicura di snprintf()
e vsnprintf()
è fornita da ffmpeg. Puoi controllare la fonte qui (suggerito).
Ho provato il codice di @Valentin Milea ma ho degli errori di violazione di accesso. L’unica cosa che ha funzionato per me è stata l’implementazione di Insane Coding: http://asprintf.insanecoding.org/
Nello specifico, stavo lavorando con il codice legacy VC ++ 2008. Dall’implementazione di Insane Coding (scaricabile dal link sopra), ho usato tre file: asprintf.c
, asprintf.h
e vasprintf-msvc.c
. Altri file erano per altre versioni di MSVC.
[EDIT] Per completezza, i loro contenuti sono i seguenti:
asprintf.h:
#ifndef INSANE_ASPRINTF_H #define INSANE_ASPRINTF_H #ifndef __cplusplus #include #else #include extern "C" { #endif #define insane_free(ptr) { free(ptr); ptr = 0; } int vasprintf(char **strp, const char *fmt, va_list ap); int asprintf(char **strp, const char *fmt, ...); #ifdef __cplusplus } #endif #endif
asprintf.c:
#include "asprintf.h" int asprintf(char **strp, const char *fmt, ...) { int r; va_list ap; va_start(ap, fmt); r = vasprintf(strp, fmt, ap); va_end(ap); return(r); }
vasprintf-msvc.c:
#include #include #include #include "asprintf.h" int vasprintf(char **strp, const char *fmt, va_list ap) { int r = -1, size = _vscprintf(fmt, ap); if ((size >= 0) && (size < INT_MAX)) { *strp = (char *)malloc(size+1); //+1 for null if (*strp) { r = vsnprintf(*strp, size+1, fmt, ap); //+1 for null if ((r < 0) || (r > size)) { insane_free(*strp); r = -1; } } } else { *strp = 0; } return(r); }
Utilizzo (parte di test.c
fornita da Insane Coding):
#include #include #include "asprintf.h" int main() { char *s; if (asprintf(&s, "Hello, %d in hex padded to 8 digits is: %08x\n", 15, 15) != -1) { puts(s); insane_free(s); } }