2016-04-22 16 views
19

Napisałem ten kod, który tworzy identyfikatory zawierające uniwersalne nazwy postaci poprzez łączenie tokenów.Tworzenie identyfikatorów zawierających uniwersalne nazwy znaków poprzez łączenie tokena

//#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; 
} 

Ten kod działa dobrze z gcc 4.8.2 with -fextended-identifiers option i gcc 5.3.1, ale nie działa z clang 3.3 z komunikatem o błędzie:

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

i lokalnym dzyń (wersja 7.0.2 Jabłko LLVM (dzyń-700.1.81)) z komunikatem o błędzie:

$ 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. 

Kiedy użyłem -E opcję, aby kod wyjściowy kompilatory z makro rozszerzonym, gcc 5.3.1 emitowane t jego:

# 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; 
} 

lokalny dzyń emitowany to:

# 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; 
} 

Jak widać, identyfikatory zadeklarowane i stosowane w printf() meczów w wyjście GCC, ale nie są one zgodne z wyjściem dzyń za.

Wiem, że tworzenie uniwersalnych nazw znaków poprzez łączenie tokenów powoduje wywołanie niezdefiniowanego zachowania.

Cytat N1570 5.1.1.2 faz Tłumaczenie:

Jeżeli sekwencja znaków, które mecze składnię uniwersalnej nazwy znaków jest produkowany przez token konkatenacji (6.10.3.3), zachowanie jest niezdefiniowane.

myślałem, że ta sekwencja znaków \u306d\u3053 może „dopasować składni uniwersalnego charakteru nazwy” ponieważ zawiera uniwersalne imiona postaci jak jego fragmentu. Sądziłem również, że "dopasowanie" może oznaczać, że cały token wygenerowany przez konkatenację oznacza jedną uniwersalną nazwę postaci, i dlatego to niezdefiniowane zachowanie nie jest wywoływane w tym kodzie.

Reading PRE30-C. Do not create a universal character name through concatenation znalazłem komentarz mówiąc tego rodzaju konkatenacji jest dozwolone: ​​

Co jest zabronione, aby utworzyć nowy UCN poprzez konkatenacji. Jak robi

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

tylko łączenie rzeczy, które dzieje się zawierać UCNs wszędzie jest w porządku.

Dziennik, który pokazuje, że a code example like this case (but with 4 characters) został zastąpiony przez another code example.

Czy mój przykład kodu wywołuje niektóre niezdefiniowane zachowania (nie ograniczając się do tych wywoływanych przez tworzenie uniwersalnych nazw znaków poprzez łączenie tokenów)? A może to błąd w klangu?

+0

Jeśli chodzi o mnie, gcc 5.3.1 wygląda o wiele gorzej ... odkomentuj '// printf ("% d \ n ", CAT (\ u306d, \ u3053)); narzeka. Z brzękiem uzyskuję co najmniej spójne wyniki - mogę odkomentować wszystkie linie i zaakceptować je, ponieważ wynik użycia "CAT" konsekwentnie różni się od bezpośredniego konkatenacji. – grek40

+0

@ grek40 gcc 6.1 nie narzeka na to, wydaje się ale w gcc 5.3.1 (nie wypróbowany)? – user1887915

+1

trigrafów, digrafów, UCN ... po prostu powiedz NIE. – chqrlie

Odpowiedz

7

Twój kod nie wywołuje niezdefiniowanego zachowania, o którym wspominasz, ponieważ uniwersalna nazwa znaku (6.4.3) nie jest tworzona przez łączenie tokenów.

A według 6.10.3.3, ponieważ zarówno po lewej i po prawej stronie jest operatorem ## identyfikator i wytworzona znacznik jest również ważna znacznik przerób (identyfikator zbyt), użytkownik sam ## nie wyzwalania niezdefiniowane zachowanie.

Po przeczytaniu opisu o identyfikatorze (6.4.2, D.1, D.2), uniwersalnych nazwach znaków (6.4.3), jestem prawie pewien, że jest to bardziej jak błąd w preprocesorze klang, który traktuje identyfikator wygenerowany przez łączenie tokena i normalny identyfikator w inny sposób.

+0

+1, właśnie to. 5.1.1.2 nie mówi, że nie można manipulować całymi UCN w preprocesorze; Mówi, że nie można tworzyć UCN z ich części składowych (np. Tworzenie UCN w wyniku "\ U30 ## 53" jest nielegalne). Krótko mówiąc, GCC robi to dobrze, a Clang nie. –

Powiązane problemy