Я написал этот код, который создает идентификаторы, содержащие универсальные имена символов, через конкатенацию токенов.
//#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?