2015-04-13 8 views
12

fprintf() famiglia di funzioni hanno 5 bandiera caratteri '-', '+', ' ', '#', '0'.Qual è il comportamento quando viene ripetuto un flag identificatore printf?

Qual è il comportamento specificato, se presente, quando un flag è ripetuto?

#include <stdio.h> 
int main(void) { 
    printf("% d\n", 12);  // 12 
    printf("%00d\n", 34);  // 34 
    printf("%++d\n", 56);  // +56 
    printf("%00*d\n", 5, 78); // 00078 
    return 0; 
} 

Con il mio gcc "i686-pc-cygwin/4.9.2" ricevo "attenzione: ripetuto '' bandiera in formato [-Wformat =]", quindi suppongo che questo è un comportamento corretto -> avvisare l'utente e consentire il flag ripetuto.

Devo ancora trovare una guida alle specifiche C99/C11 per questo problema d'angolo trovato durante il tentativo di scrivere un parser di formato.

Se il ripetuto è consentito, il seguente codice è OK. Se il ripetersi non è consentito, il 2 ° 0 è la larghezza. Quindi lo specificatore ha 2 larghezze 0 e *, che è un altro problema.

// -------v 
printf("%00*d\n", 5, 78); // 00078 
+1

FWIW, ottengo gli stessi risultati su VS 2008 e VS 2010. –

+1

Certamente non è richiesto alcun avviso, anche per una stringa di formato errata. Le stringhe di formato possono essere costruite in fase di esecuzione; nel caso generale, il compilatore non può dire se è corretto. Alcuni compilatori, come gcc, avvertono di una stringa di formato errata quando è letterale (il caso più comune). (Questo non risponde alla tua domanda se sono permessi i flag ripetuti.) –

+0

Ho visto alcune implementazioni di 'printf' e ne ho scritte almeno 4 diverse. Gestiscono tutti i flag ripetuti come equivalenti a un singolo flag, per la semplice ragione che è molto più semplice farlo e per i pochi implementatori che si chiedono a riguardo, non sembra essere errato. – chqrlie

risposta

5

A mio parere, lo standard non è chiaro su questo punto.

Gli autori di gcc erano chiaramente del parere che ripete le bandiere non sono validi, poiché gcc emette un avviso di default per qualcosa di simile:

printf("%++d\n", 42); 

ma questo non significa necessariamente dirci cosa del autori inteso come standard

I permessi standard:

zero o più bandiere (in qualsiasi ordine), che modificano il significato della specifica di conversione .

Le bandiere sono -, +, spazio, # e 0. La frase "Zero o più bandiere * è, credo, specificamente destinati a permettere diversi bandiere per essere combinati, ad esempio, questo:.

#include <stdio.h> 
int main(void) { 
    printf("|%6x|\n", 0x123); 
    printf("|%-6x|\n", 0x123); 
    printf("|%#6x|\n", 0x123); 
    printf("|%-#6x|\n", 0x123); 
    printf("|%#-6x|\n", 0x123); 
} 

è valido e produce questo risultato:

| 123| 
|123 | 
| 0x123| 
|0x123 | 
|0x123 | 

In altri contesti, lo standard indica esplicitamente se un costrutto può o non può essere ripetuto.Ad esempio, long long int è diverso da long int e long int int è un errore di sintassi, d'altra parte lo standard dice esplicitamente (N1570 6.7.3p5) quello:

Se lo stesso qualificatore appare più di una volta nella stessa specificatore-qualificatore-list, direttamente o tramite uno o più typedefs, il comportamento è lo stesso come se fosse apparso solo una volta.

La mancanza di una tale affermazione qui mi fa sospettare che gli autori dello standard non abbiano considerato il caso di ripetere la stessa bandiera.

Se non sono corretto su questo, e il comitato ha inteso un flag ripetuto per essere equivalente a un singolo flag, quindi il parser del formato dovrebbe trattarli come equivalenti. Se sono corretto, il comportamento di ripetere lo stesso flag non è definito e la tua implementazione può fare tutto ciò che vuoi, incluso trattarli come equivalenti a un singolo flag.

In entrambi i casi, sei libero di emettere un avviso se lo desideri. Anche se lo standard definisce il comportamento di una bandiera ripetuta, è ancora discutibilmente di stile scadente e merita di essere avvertito.

+0

@ShafikYaghmour 'printf ("% d ", 10.1);' inoltre non fa in modo che gcc rilasci qualcosa oltre un avvertimento, anche con '-pedantic-errors'. –

+0

@ T.C .: Per quanto riguarda lo standard, 'printf ("% d ", 10.1)' ha semplicemente un comportamento non definito. Un'implementazione può diagnosticarlo o addirittura rifiutarlo, ma non è * obbligatorio * fare qualcosa in particolare. Se è in un contesto come 'if (0) printf ("% d ", 10.0);' it * non dovrebbe * essere rifiutato. –

+0

Lo so. Il mio commento è stato in risposta al commento di Shafik (poiché cancellato) che gcc non sta aggiornando l'avviso di ripetizione di un errore con '-pedantic-errors' indica che pensa che sia conforme. –

2

Nello standard C (7.21.6.1 La funzione fprintf) c'è scritto soltanto che specifica

4 Ogni conversione è introdotto dal carattere%. Dopo la %, seguito si visualizzano in sequenza:

- zero o più flag (in qualsiasi ordine) che modificano il significato della specifica conversione.

Quindi suppongo che le bandiere possano essere ripetute. Altrimenti ci sarebbero alcune restrizioni.

2

Lo standard dice:

7.19.6.1/4 Zero o più bandiere (in qualsiasi ordine) che modificano il significato della specifica di conversione.

"zero o più flag" è ovviamente inteso per consentire la specificazione di più di un flag. Ha senso che se un flag viene ripetuto, ha lo stesso significato del flag che appare solo una volta.

Problemi correlati