2010-03-01 15 views
22

Con GCC, posso specificare __attribute__((format(printf, 1, 2))), dicendo al compilatore che questa funzione accetta parametri vararg che sono specificatori del formato printf.__attribute __ ((formato (printf, 1, 2))) per MSVC?

Questo è molto utile nei casi in cui mi avvolgo ad es. la famiglia di funzioni vsprintf. Posso avere extern void log_error(const char *format, ...) __attribute__((format(printf, 1, 2)));

E ogni volta che chiamo questa funzione, gcc verificherà che i tipi e il numero di argomenti si conformino agli specificatori di formato dati come farebbero per printf e emetteranno un avviso se non lo sono.

Il compilatore Microsoft C/C++ ha qualcosa di simile?

risposta

4

Mentre GCC controlla gli specificatori di formato quando -Watformat è abilitato, VC++ non esegue tale controllo, anche per le funzioni standard, quindi non esiste un equivalente a questo __attribute__ perché non esiste un equivalente a -Wformat.

Penso che l'enfasi di Microsoft su C++ (evidenziato dal mantenimento della conformità ISO per C++ pur supportando solo C89) possa essere in parte la ragione per cui VC++ non ha il controllo degli identificatori di formato; in C++ utilizzando gli identificatori di formato <iostream> non necessari.

+1

In realtà, sembra che tale controllo non esca: vedere [risposta di sixlettervariables] (http://stackoverflow.com/questions/2354784/attribute-formatprintf-1-2-for-msvc/6849629#6849629). –

+0

@RaphaelISP: se leggi il link in quella risposta, vedrai che le annotazioni SAL vengono ignorate a meno che non sia l'opzione [/analyze](http://msdn.microsoft.com/en-us/library/ms173498.aspx) è specificato e questo è disponibile solo nelle edizioni Enterprise di Visual Studio. Inoltre i controlli che vengono eseguiti non sono dello stesso tipo di GCC. Una risposta alternativa dopo un anno dopo aver chiesto appena giustificato un downvote della risposta accettata senza comprendere l'applicabilità dell'alternativa. – Clifford

+1

@Raphae:/analyze esegue un numero di verifiche relative alle stringhe in stile printf (vedere [C6270-C6274] (http://msdn.microsoft.com/en-us/library/a5b9aa09.aspx) e altri, ma non sono così approfonditi come quelli di GCC. L'unico in Enterprise è solo un problema di "tipo", come si dovrebbe evitare VS se non lo si sta acquistando. – user7116

1

c'è un articolo interessante sul tema sul Codice Progetto: "Modelli con C++ per avvio di convalida" da Alexander Gorobets http://www.codeproject.com/KB/cpp/ValidateprintfFunction.aspx

ho modificato in modo che ho una macro PRINTF_VALIDATE(format, ...) che registra tutto errori di formato allo statup del programma (non è necessario eseguire il codice). Produce qualcosa di simile:

test.cpp(147) : error : 'printf' format character 'f' at position 1 does not match parameter type INT 
test.cpp(147) : error : 'printf' too many arguments (3 instead of 2) 

Si può usare per esempio come questo:

#define LOG(fmt, ...) do { PRINTF_VALIDATE(fmt, __VA_ARGS__); WriteLog(fmt, __VA_ARGS__); } while(0) 

questo non è così utile come supporto del compilatore, ma funziona su Visual Studio 2005 ...

15

Usando SAL Annotations è possibile utilizzare _Printf_format_string_ (come di VS2k8 o VS2k10) o __format_string (per VS2k5):

#undef FORMAT_STRING 
#if _MSC_VER >= 1400 
# include <sal.h> 
# if _MSC_VER > 1400 
# define FORMAT_STRING(p) _Printf_format_string_ p 
# else 
# define FORMAT_STRING(p) __format_string p 
# endif /* FORMAT_STRING */ 
#else 
# define FORMAT_STRING(p) p 
#endif /* _MSC_VER */ 

/* use /analyze or _USE_ATTRIBUTES_FOR_SAL for checking */ 
extern void log_error(FORMAT_STRING(const char* format), ...); 
+3

Ignorato al di fuori delle edizioni "Enterprise" con l'opzione/analyze specificata. – Clifford

+0

Suggerisco di evitare VS se non si sta acquistando l'edizione aziendale. – user7116

+3

Davvero? perché? Persino la Express Edition gratuita è un compilatore C/C++ completamente capace con un debugger di prima classe. Potrebbe essere necessario "Enterprise" (principalmente le aziende), ma ciò che "Enterprise" porta è aggiuntivo al compilatore principale e al debugger. – Clifford

2

Come accennato in precedenza da @RustyX il controllo del formato printf è ora supportato per impostazione predefinita as of VC2015. Questo è senza a /analyze pass di analisi statica. Purtroppo non esiste ancora un meccanismo per contrassegnare le funzioni wrapper definite dall'utente.

Ciò suggerisce la soluzione ovvia di chiamando printf. Ciò sta definendo una macro che richiama sia la funzione definita dall'utente sia lo stesso printf. Quest'ultimo su un percorso morto da ottimizzare.

Questo ha l'ulteriore vantaggio di raggiungere un certo livello di portabilità per altri compilatori.

int printf_wrapper_(const char *format, ...); 

#define printf_wrapper(...) \ 
(printf || printf(__VA_ARGS__), printf_wrapper_(__VA_ARGS__)) 

Lo svantaggio è che VC2015 esegue alcune eliminazione dead-codice rudimentale precedenti il ​​controllo formato, testando solo il codice vivo rimanente.

Pertanto, le espressioni condizionali costanti sizeof non funzioneranno. Come regola generale, se una build di debug emette il codice di runtime, verrà visualizzato l'avviso, anche se in seguito i passaggi nei build di rilascio potrebbero comunque interrompere la chiamata.

Purtroppo questo rende qualcosa di un bersaglio mobile suscettibile di cambiare nelle future versioni del compilatore. Anche se relativamente relativamente benevolo.

Problemi correlati