snprintf e Visual Studio 2010

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 che buf_size sia zero. Se buf_size è zero, non viene scritto nulla e il buffer può essere un puntatore nullo. Il valore restituito è il numero di caratteri che sarebbero stati scritti assumendo un buf_size illimitato di buf_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); } }