2013-07-02 13 views
7

Gli standard C e C++ includono tutti il ​​testo per l'effetto che se un'operazione di stringa non riesce a produrre un token letterale stringa valido, il comportamento non è definito. In C++ 11 questo è effettivamente possibile, includendo un carattere di nuova riga in una stringa raw letterale. Ma il catch-all è sempre stato presente negli standard.Stringize operator failure

C'è qualche altro modo in cui la stringa può produrre UB, dove UB o un programma mal formato non è ancora successo?

Sarei interessato a conoscere qualsiasi dialetto di C o C++ qualunque. Sono writing un preprocessore.

+3

La maggior parte delle persone fa fatica a farli lavorare, non fallire. –

+0

Hah ... Vorrei verificare che il fallimento funzioni, cioè ottenere una prova. Il trucco con le newline non aiuta perché lo intrappolo e aggiungo un '\ n'. (Bene, è un '" \\\\\ "" se stai contando i backslash.) – Potatoswatter

+0

Ok, allora non ho ottenuto quello che stai chiedendo, hai bisogno di test del preprocessore. mcpp ha una suite di convalida. –

risposta

4

L'operatore stringify (#) scappa solo \ in costanti stringa. Infatti, \ non ha alcun significato particolare al di fuori di una costante di stringa, tranne alla fine di una riga. È, quindi, un token di preelaborazione (sezione C 6.4, sezione C++ 2.5).

Di conseguenza, se abbiamo

#define Q(X) #X 

poi

Q(\) 

è una chiamata legittima: il \ è un token pre-elaborazione che non è mai convertito in un gettone, quindi è valido. Ma non puoi stringificare \; questo ti darebbe "\" che non è una stringa letterale valida. Quindi, il comportamento di cui sopra non è definito.

Ecco un banco di prova più divertente:

#define Q(A) #A 
#define ESCAPE(c) Q(\c) 
const char* new_line=ESCAPE(n); 
const char* undefined_behaviour=ESCAPE(x); 

Un caso meno interessante di una stringa i indefinita è dove il parametro in stringa sarebbe troppo lungo per essere una stringa letterale. (Gli standard raccomandano che la dimensione massima di una stringa sia almeno 65536 caratteri, ma non dice nulla sulla dimensione massima di un argomento macro, che potrebbe presumibilmente essere più grande.)

+0

Grazie! Doveva pensarci. Una stringa non terminata è già qualcosa che ho provato nella catenation di stringhe raw, e questo viene intrappolato esattamente nello stesso modo :). Il tuo caso più divertente non sembra essere UB nel preprocessore; è esattamente come scrivere '" \ x "' o mi manca qualcosa? (Le sequenze di escape sono tradotte in seguito.) – Potatoswatter

+0

@Potatoswatter: un letterale stringa contiene s-char, sequenze di escape e nomi di caratteri universali. '\ x' non è uno dei precedenti. Quindi '" \ x "' non è un letterale stringa valido, il modo in cui lo vedo, e quindi il modo in cui il preprocessore si occupa di 'ESCAPE (x)' (o, per quello, 'ESCAPE (*)') non è definito. Quindi il preprocessore potrebbe, se lo ha scelto, sostituirli entrambi con una faccina. – rici

+0

Almeno in C++, "Le sequenze di escape in cui il carattere che segue la barra rovesciata non è elencata nella Tabella 7 sono condizionalmente supportate, con semantica definita dall'implementazione." Quindi, per un preprocessore discreto, penso che la trappola sarebbe un po 'restrittiva. Ma hai ragione, questa è la grammatica :) Grazie ancora! – Potatoswatter