2010-06-23 8 views
10

Vorrei scrivere una routine come printf, non dal punto di vista funzionale, ma preferirei che la routine avesse le stesse caratteristiche di controllo di compilazione di printf.Come ottenere avvisi o errori in fase di compilazione in stile printf

Per esempio se ho:

{ 
    int i; 
    std::string s; 
    printf("%d %d",i); 
    printf("%d",s.c_str()); 
} 

Il compilatore si lamenta in questo modo:

1 cc1plus: warnings being treated as errors 
2 In function 'int main()': 
3 Line 8: warning: too few arguments for format 
4 Line 9: warning: format '%d' expects type 'int', but argument 2 has type 'const char*' 

code example

Sono printf e co funzioni speciali che gli ossequi compilatore diverso o c'è qualche trucco per far funzionare tutto questo su qualsiasi funzione definita dall'utente? I compilatori specifici a cui sono interessato sono gcc e msvc

risposta

17

Diversi compilatori potrebbero implementare questa funzionalità in modo diverso. In GCC è implementato tramite l'identificatore __attribute__ con l'attributo format (leggi a proposito lo here). Il motivo per cui il compilatore esegue il controllo è solo che nei file di intestazione standard fornite con GCC la funzione printf viene dichiarato con __attribute__((format(printf, 1, 2)))

Esattamente nello stesso modo in cui è possibile utilizzare l'attributo format per estendere la stessa funzionalità format-controllo per la vostra proprie funzioni variadiche che utilizzano gli stessi specificatori di formato come printf.

Questo funziona solo se il parametro che passa convenzione e gli specificatori di formato che si utilizzano sono uguali a quelli utilizzati dalle funzioni standard printf e scanf. I controlli sono codificati nel compilatore. Se stai usando una convenzione diversa per il passaggio di argomenti variadici, il compilatore non ti aiuterà a controllarlo.

+4

Può fare un po 'più di printf e scanf; l'elenco dei documenti attuali è "printf, scanf, strftime, gnu_printf, gnu_scanf, gnu_strftime o strfmon" – Cascabel

+2

È fantastico. Spero che CodeGear/Embarcadero metta questa caratteristica nel loro compilatore in futuro. –

3

printf() e gli amici non sono speciali perché accettano un numero variabile di argomenti: le funzioni definite dall'utente possono accettare anche un numero variabile di argomenti. Sono speciali perché il loro comportamento è definito dallo standard, quindi il compilatore sa quale dovrebbe essere la correlazione tra la stringa di formato e gli argomenti passati alla funzione.

In modo efficace, il compilatore conosce quanti argomenti vengono passati alla funzione quando viene chiamato, quindi analizza la stringa di formato e confronta il numero previsto e i tipi di argomenti con gli argomenti effettivamente passati alla funzione ed emette un avviso se non corrispondono.

Se si utilizza C++, evitare di scrivere le proprie funzioni variadiche; ci sono alcuni buoni motivi per usarli nella maggior parte dei progetti. Ad esempio, se si sta eseguendo la formattazione, utilizzare i flussi o una libreria come Boost Format. Qualsiasi problema risolvibile mediante una funzione variadica può essere risolto utilizzando una funzione non-variadica e in quasi tutti i casi il risultato è più elegante, idiomatico e sicuro per il tipo.

+4

In realtà ci sono molti buoni motivi per evitare flussi e Boost quando si codifica in C++, ma tutti sono specifici del dominio. Molti di noi eseguono una certa quantità di lavoro specifico del dominio, quindi dovremmo cercare di non perdere di vista il fatto che ci sono un numero considerevole di persone per le quali molte funzionalità del C++ sono troppo costose. –

+1

@ dash-tom-bang: Sì, hai ragione: ci sono certamente degli scenari in cui sono utili. –

1

In realtà printf non ha alcuna inerente sicurezza in fase di compilazione. Succede solo che alcuni compilatori più recenti hanno implementato controlli speciali dato che sanno esattamente cosa significa una stringa di formato in termini di parametri aggiuntivi. Quando si utilizza ... come parametro si sta dicendo che si desidera accettare argomenti arbitrari e accettare la piena responsabilità per assicurarsi che siano corretti. Non c'è modo per il compilatore di controllarli per la sicurezza del conteggio/tipo.

Invece di cercare di ottenere il compilatore in questo modo, provare a utilizzare l'approccio utilizzato dagli stream standard: utilizzare una funzione (o modello) o un operatore che restituisce un riferimento a this per consentire il concatenamento. Quindi il compilatore sarà in grado di dirti subito quando gli argomenti non corrispondono a ciò che è previsto/supportato.

1

Qualche tempo fa qualcuno ha postato una stringa mpl ::. Penso che potrebbe essere entrato nella biblioteca. In tal caso, è possibile implementare qualcosa di simile fornendo la stringa del modello come parametro del modello (una mpl :: string) e quindi utilizzando alcune abilità di meta-programmazione piuttosto profonde per analizzare i bit di formattazione al suo interno. Quindi useresti queste informazioni per scegliere un'implementazione con il numero e il tipo di argomenti appropriati.

No, non ho intenzione di farlo per voi: P Sarebbe abbastanza difficile. Tuttavia, credo che sarebbe possibile.

Problemi correlati