Подтвердить что ты не робот

Создание идентификаторов, содержащих имена универсальных символов, посредством конкатенации маркеров

Я написал этот код, который создает идентификаторы, содержащие универсальные имена символов, через конкатенацию токенов.

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

Этот код хорошо работал с gcc 4.8.2 с опцией -fextended-identifiers и gcc 5.3.1, но не работал с clang 3.3 с сообщением об ошибке:

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

и локальный clang (версия Apple LLVM версии 7.0.2 (clang-700.1.81)) с сообщением об ошибке:

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

Когда я использовал параметр -E для вывода кода вывода компиляторов с расширенным макросом, gcc 5.3.1 испустил это:

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

local clang испустил это:

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

Как вы видите, идентификаторы, объявленные и используемые в printf(), соответствуют выходу gcc, но они не совпадают с выходом clang.

Я знаю, что создание универсальных имен символов через конкатенацию токенов вызывает поведение undefined.

Цитата из N1570 5.1.1.2 Фазы перевода:

Если последовательность символов, которая соответствует синтаксису универсального символьного имени, создаваемого токеном конкатенация (6.10.3.3), поведение undefined.

Я думал, что эта последовательность символов \u306d\u3053 может "соответствовать синтаксису универсального символьного имени", потому что она содержит универсальные имена символов в качестве подстроки. Я также подумал, что "совпадение" может означать, что весь токен, созданный посредством конкатенации, обозначает одно универсальное имя символа, и поэтому это поведение undefined не вызывается в этом коде.

Чтение PRE30-C. Не создавайте универсальное имя символа через конкатенацию, я нашел комментарий, говорящий, что такой тип конкатенации разрешен:

Что запрещено, чтобы создать новый UCN через конкатенацию. Как делать

правопреемником (\ u0001,0401, а, б, 4)

просто конкатенировать материал, который, как всегда, содержит UCN, в порядке.

И журнал, который показывает, что пример кода, подобный этому случаю (но с 4 символами), заменяется на другой пример кода.

В моем примере кода вызывается поведение undefined (не ограничиваясь теми, которые вызываются путем создания универсальных имен символов через конкатенацию токенов)? Или это ошибка в clang?

4b9b3361

Ответ 1

Ваш код не запускает описанное вами поведение undefined, поскольку универсальное имя символа (6.4.3) не создается путем объединения маркеров.

И, согласно 6.10.3.3, так как и левая, и правая стороны оператора ## является идентификатором, а полученный токен также является допустимым токеном предварительной обработки (также идентификатором), оператором ## сам по себе не вызывает поведение undefined.

После прочтения описания идентификаторов (6.4.2, D.1, D.2), универсальных имен символов (6.4.3), я уверен, что это больше похоже на ошибку в препроцессоре clang, которая обрабатывает идентификатор созданных путем объединения маркеров и обычного идентификатора.