Il backslash è accettabile nelle direttive C e C ++ #include?

Ci sono due separatori di percorso in uso comune: la barra di avanzamento di Unix e la barra rovesciata di DOS. Riposa in pace, colon Mac classico. Se usati in una direttiva #include, sono uguali secondo le regole degli standard C ++ 11, C ++ 03 e C99?

C99 dice (§6.4.7 / 3):

Se i caratteri ‘, \, “, // o / * si verificano nella sequenza tra i delimitatori , il comportamento non è definito. Analogamente, se i caratteri’, \, // o / * si verificano nella sequenza tra i “delimitatori”, il comportamento non è definito.

(nota in calce: quindi, sequenze di caratteri che assomigliano a sequenze di escape causano comportamenti indefiniti).

C ++ 03 dice (§2.8 / 2):

Se uno dei caratteri ‘o \, o una delle sequenze di caratteri / * o // appare in una sequenza di q-char- o in una sequenza di h-char, o il carattere “appare in una sequenza di h-char, il il comportamento non è definito.

(nota in calce: quindi, sequenze di caratteri che assomigliano a sequenze di escape causano comportamenti indefiniti).

C ++ 11 dice (§2.9 / 2):

L’aspetto di uno dei caratteri ‘o \ o di una delle sequenze di caratteri / * o // in una sequenza di q-char o in una sequenza di h-char è condizionalmente supportato con semantica definita dall’implementazione, così come l’aspetto di il personaggio “in una sequenza h-char.

(nota: una sequenza di caratteri che assomiglia a una sequenza di escape può causare un errore, essere interpretata come il carattere corrispondente alla sequenza di escape o avere un significato completamente diverso, a seconda dell’implementazione).

Pertanto, sebbene qualsiasi compilatore possa scegliere di supportare una barra rovesciata in un percorso #include , è improbabile che qualsiasi fornitore di compilatori non supporti la barra diretta e che i backslash possano aggirare alcune implementazioni in virtù della formazione di codici di escape. (Modifica: apparentemente MSVC richiedeva il backslash. Forse altri su piattaforms derivate da DOS erano simili … Hmmm … cosa posso dire.)

C ++ 11 sembra allentare le regole, ma “supportato in modo condizionale” non è significativamente migliore di “causa un comportamento indefinito”. Il cambiamento fa più riflettere l’esistenza di alcuni compilatori popolari piuttosto che descrivere uno standard portatile.

Naturalmente, nulla in nessuno di questi standard dice che esiste qualcosa come i percorsi. Ci sono filesystem là fuori senza percorsi! Tuttavia, molte librerie assumono pathname, tra cui POSIX e Boost, quindi è ragionevole volere un modo portabile per riferirsi a file all’interno di sottodirectory.

La barra in avanti è la via corretta; il pre-compilatore farà tutto il necessario su ogni piattaforma per ottenere il file corretto.

Blackslash è un comportamento indefinito e anche con una barra devi stare attento. Lo standard C99 afferma:

Se i caratteri ‘, \, “, // o / * si verificano nella sequenza tra i delimitatori , il comportamento non è definito. Analogamente, se i caratteri’, \, // o / * si verificano nella sequenza tra i “delimitatori”, il comportamento non è definito.

Dipende da cosa intendi per “accettabile”.

Ci sono due sensi in cui le barre sono accettabili e le backslash non lo sono.

Se stai scrivendo C99, C ++ 03 o C1x, i backslash non sono definiti, mentre le barre sono legali, quindi in questo senso i backslash non sono accettabili.

Ma questo è irrilevante per la maggior parte delle persone. Se stai scrivendo C ++ 1x, in cui i backslash sono supportati in modo condizionale e la piattaforma che stai codificando li supporta, sono accettabili. E se stai scrivendo un “dialetto esteso” di C99 / C ++ 03 / C1x che definisce i backslash, lo stesso accordo. E, cosa ancora più importante, questa nozione di “accettabile” è praticamente priva di significato nella maggior parte dei casi. Nessuno degli standard C / C ++ definisce cosa significano le barre (o cosa significano i backslash quando sono condizionati). I nomi delle intestazioni sono mappati ai file sorgente in un modo, periodo definito dall’implementazione. Se hai una gerarchia di file e ti stai chiedendo se usare le barre rovesciate o le barre per riferirti a loro in modo accettabile nelle direttive #include, la risposta è: nessuno dei due è portatile. Se si desidera scrivere codice veramente portatile, non è ansible utilizzare gerarchie di file di intestazione, infatti, la soluzione migliore è scrivere tutto in un unico file sorgente, e non #includere nulla tranne le intestazioni standard.

Tuttavia, nel mondo reale, le persone spesso vogliono “abbastanza portatile”, non “strettamente portatile”. Lo standard POSIX impone cosa significano le slash e, anche al di là di POSIX, la maggior parte delle piattaforms moderne, inclusi Win32 (e Win64), i cross-compilers per piattaforms embedded e mobili come Symbian, ecc. Tratta il modo POSIX, almeno fino a Direttive di C / C ++ #include. Qualsiasi piattaforma che non sia, probabilmente non avrà alcun modo per voi di ottenere il vostro albero sorgente su di esso, elaborare il vostro makefile / etc., E così via, quindi le direttive #include saranno l’ultima delle vostre preoccupazioni. Se questo è quello che ti interessa, allora i tagli sono accettabili, ma i backslash non lo sono.

Lo standard dice per # include che:

ricerca una sequenza di punti definiti dall’implementazione per un’intestazione identificata univocamente dalla sequenza specificata tra i delimitatori e causa la sostituzione di tale direttiva con l’intero contenuto dell’intestazione. Come vengono specificati i posti o l’intestazione identificata è definita dall’implementazione.

Nota l’ultima frase.

Usa sempre le barre in avanti: funzionano su più piattaforms. Backslash causa tecnicamente un comportamento non definito in C ++ 03 (2.8 / 2 nello standard).