2015-10-22 14 views
15

Perché lo printf stampa uno spazio invece di arrestarsi quando utilizzo il carattere NULL dalla tabella ASCII? Questo è ciò che intendo:Passare byte nullo tramite identificatore di formato in `printf`

printf("Hello%c, world", 0); //Hello , world 
printf("Hello%c, world", '\0'); //Hello , world 

Solo quando ho messo il carattere di escape nella stringa stessa printf interrompe la stringa:

printf("Hello\0, world"); //Hello 

Ho provato questo su Windows 8, Windows 10 (usando Cygwin, MinGW , Netbeans, Code :: Blocks), XUbuntu, è lo stesso.

Dov'è il problema? Ho chiesto a uno dei miei amici, ma ha detto che non ha alcun problema, che tutti e tre gli esempi sono stati eseguiti allo stesso modo.

+0

Perché pensi che il primo 2 debba stampare solo Ciao? [esempio C++] (http://coliru.stacked-crooked.com/a/1d7e28cf27e49f71) – rozina

+2

Perché, 0 è il numero del terminatore NULL/zero nella tabella ASCII e il suo equivalente carattere di escape è '\ 0'. –

+2

@rozina, perché ''\ 0'' è il carattere terminatore null? –

risposta

22

printf("Hello\0, world"); utilizza il suo parametro come C-stringa quindi decodifica finché non trova un carattere NUL, quindi è automatico appena \0, ignorando quanto segue.

printf("Hello%c, world", 0); decodifica suo parametro (finché non trova dentro un carattere NUL - cioè dopo d), nel frattempo trova una %c, quindi sostituisce con il carattere passato come parametro (il cui codice ASCII è NUL) e poi invia al terminale un carattere NUL, quindi continua.

manuale Printf dice:

Queste funzioni scrivere l'output sotto il controllo di una stringa di formato che specifica come le successive argomentazioni [...] vengono convertiti per uscita.

+1

Hai qualche riferimento allo Standard su questo? – emlai

+2

Questo è per definizione di cosa è una stringa C e per il formato printf. –

+1

La domanda rimane ancora - perché in alcuni compilatori (come quello del mio amico) i tre esempi eseguono lo stesso. –

6

Si sta prendendo una dipendenza da un dettaglio di implementazione printf(). La funzione di output del terminale di basso livello richiede la lunghezza della stringa come argomento. Ci sono due modi per printf() per farlo.

Il modo alquanto ovvio è quello primo formato stringa, quindi uso strlen(). È quello che speravi.

Ma questo è inefficiente perché richiede un doppio passaggio attraverso il buffer di stringa e aggiungendo 0. L'altro modo per farlo è tenere traccia della lunghezza della stringa formattata mentre sostituendo i campi, semplicemente incrementando per ogni personaggio aggiunto. Dal momento che continua oltre il% c, avrai ora la lunghezza maggiore che include tutto il passato% c. Ciò che la funzione terminale fa con lo 0 incorporato è anche un dettaglio di implementazione, dato che non è un carattere stampabile. Vedendolo sostituito con uno spazio non è raro.

Un modo sicuro per fare questo è non affidarsi ai dettagli di implementazione.

1
printf("Hello%c, world", 0); //Hello , world 
printf("Hello%c, world", '\0'); //Hello , world 

In entrambi i casi, si sta cercando di stampare il valore del carattere corrispondente al codice di carattere 0, che non è un carattere stampabile. Non ho trovato capitolo e versetto su di esso, ma sospetto che il comportamento di provare a stampare un valore di carattere nul non sia specificato o forse non definito. Ad ogni modo, non mi aspetto che venga trattato come un terminatore di stringhe in questo caso.

printf("Hello\0, world"); //Hello 

In questo caso, il carattere nul è parte della stringa costante e viene interpretato dal compilatore come terminatore stringa.

+0

NUL char è definito come un tipo NOP per l'output. –

+1

@ Jean-BaptisteYunès: Capitolo e verso? Non sono riuscito a trovare alcun linguaggio definitivo nello standard, ma cercare un pdf su un iPad è una specie di rompicapo. –

+0

standard ASCII. ** 7,24 ** ** NUL ** (** NULL **). Un carattere di controllo utilizzato per eseguire il riempimento o il riempimento del tempo. I caratteri NUL possono essere inseriti o rimossi da un flusso di dati senza influire sul contenuto informativo di quel flusso, ma tale azione potrebbe influire sul layout delle informazioni e/o sul controllo delle apparecchiature. –

0

In breve: %c significa per stampare un carattere, in modo printf stampa il carattere NUL cui valore è 0. NUL è a caratteri non stampabili. Quindi possiamo vedere solo uno spazio lì.

"Hello \ 0, world" è una stringa letterale, il risultato di strlen("Hello\0, world") è 5. Quindi printf stamperà il risultato "Ciao".

Si può vedere di più sul sito cppreference: string literal

Una stringa di caratteri letterale è una sequenza di zero o più caratteri multibyte racchiusi tra virgolette, come in "xyz". Il carattere null ('\ 0') viene sempre aggiunto al letterale stringa, quindi, una stringa letterale "Hello" è un const char [6] contenente i caratteri 'H', 'e', ​​'l', 'l' , '0' e '\ 0'. Se un letterale stringa ha caratteri null incorporati, rappresenta un array che contiene più di una stringa.

Problemi correlati