2016-04-22 11 views
19

Ho scritto questo codice che crea identificatori contenenti nomi di caratteri universali tramite concatenazione di token.Creazione di identificativi contenenti nomi di caratteri universali tramite concatenazione di token

//#include <stdio.h> 
int printf(const char*, ...); 

#define CAT(a, b) a ## b 

int main(void) { 
    //int \u306d\u3053 = 10; 
    int CAT(\u306d, \u3053) = 10; 

    printf("%d\n", \u306d\u3053); 
    //printf("%d\n", CAT(\u306d, \u3053)); 

    return 0; 
} 

Questo codice ha funzionato bene con gcc 4.8.2 with -fextended-identifiers option e gcc 5.3.1, ma non ha funzionato con clang 3.3 con il messaggio di errore:

prog.c:10:17: error: use of undeclared identifier 'ねこ' 
     printf("%d\n", \u306d\u3053); 
        ^
1 error generated. 

e clang locale (versione di Apple LLVM 7.0.2 (clang-700.1.81)) con il messaggio di errore:

$ clang -std=c11 -Wall -Wextra -o uctest1 uctest1.c 
warning: format specifies type 'int' but the argument has type 
     '<dependent type>' [-Wformat] 
uctest1.c:10:17: error: use of undeclared identifier 'ねこ' 
     printf("%d\n", \u306d\u3053); 
        ^
1 warning and 1 error generated. 

Quando ho usato -E opzione per avere il codice di uscita compilatori con la macro espansa, gcc 5.3.1 emessa t la sua: clang

# 1 "main.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "/usr/include/stdc-predef.h" 1 3 4 
# 1 "<command-line>" 2 
# 1 "main.c" 

int printf(const char*, ...); 



int main(void) { 

int \U0000306d\U00003053 = 10; 

printf("%d\n", \U0000306d\U00003053); 


return 0; 
} 

locale emesso questa:

# 1 "uctest1.c" 
# 1 "<built-in>" 1 
# 1 "<built-in>" 3 
# 326 "<built-in>" 3 
# 1 "<command line>" 1 
# 1 "<built-in>" 2 
# 1 "uctest1.c" 2 

int printf(const char*, ...); 



int main(void) { 

int \u306d\u3053 = 10; 

printf("%d\n", ねこ); 


return 0; 
} 

Come si vede, gli identificatori dichiarati e utilizzati in printf() partite in output di gcc, ma non corrispondono in uscita di clang.

So che la creazione di nomi di caratteri universali tramite concatenazione di token richiama un comportamento non definito.

Citazione di N1570 5.1.1.2 fasi di traduzione:

Se una sequenza di caratteri che corrisponde la sintassi di un nome di carattere universale è prodotto con gettone concatenazione (6.10.3.3), il comportamento è indefinito.

ho pensato che questo sequenza di caratteri \u306d\u3053 può "corrispondere alla sintassi di un nome di carattere universale" perché contiene i nomi dei personaggi universali come la sua sottostringa. Ho anche pensato che "match" può significare che l'intero token prodotto tramite concatenazione sta per un nome di carattere universale, e che quindi questo comportamento indefinito non è invocato in questo codice.

lettura PRE30-C. Do not create a universal character name through concatenation, ho trovato un commento che dice questo tipo di concatenazione è consentito:

Ciò che è proibito, per creare una nuova UCN tramite concatenazione. Come fare

assegnare (\ u0001,0401, a, b, 4)

solo roba concatenando che sembra contenere UCNs ovunque va bene.

E un registro che mostra che a code example like this case (but with 4 characters) viene sostituito con another code example.

Il mio esempio di codice richiama alcuni comportamenti non definiti (non limitati a quelli invocati producendo nomi di caratteri universali tramite concatenazione di token)? Oppure si tratta di un bug in clang?

+0

Per quanto mi riguarda, gcc 5.3.1 sembra molto peggio ... decomprimere il '// printf ("% d \ n ", CAT (\ u306d, \ u3053));' linea e si lamenta. Con clang ottengo risultati consistenti almeno - Posso decommentare tutte le righe e lo accetta, poiché il risultato dell'uso di 'CAT' è consistentemente diverso dalla concatenazione diretta. – grek40

+0

@ grek40 gcc 6.1 non se ne lamenta, sembra un ma in gcc 5.3.1 (non provato)? – user1887915

+1

trigraphs, digraphs, UCN ... basta dire NO. – chqrlie

risposta

7

Il codice non attiva il comportamento non definito che si menziona, poiché il nome carattere universale (6.4.3) non viene generato dalla concatenazione di token.

E, secondo 6.10.3.3, come sia il lato sinistro e il lato destro dell'operatore ## è un identificatore e il token di prodotto è anche un gettone di pre-elaborazione valida (un identificatore troppo), il ## operatore stesso non grilletto un comportamento indefinito.

Dopo aver letto la descrizione dell'identificatore (6.4.2, D.1, D.2), i nomi dei caratteri universali (6.4.3), sono abbastanza sicuro che è più simile a un bug nel preprocessore clang, che tratta identificatore prodotto dalla concatenazione di token e dall'identificatore normale in modo diverso.

+0

+1, precisamente questo. 5.1.1.2 non dice che non è possibile manipolare interi UCN nel preprocessore; Dice che non puoi creare UCN dalle loro parti costitutive (ad esempio, creare un UCN come conseguenza di '\ U30 ## 53' è illegale). Per farla breve, GCC lo sta facendo bene e Clang no. –

Problemi correlati