トークン連結によってユニバーサル文字名を含む識別子を作成するこのコードを作成しました。
//#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
オプション付きそして5.3.1 より、しかし、クラン 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;
}
ローカル 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 の出力では一致しません。
トークン連結によってユニバーサル文字名を作成すると、未定義の動作が発生することはわかっています。
引用元N15705.1.1.2 翻訳フェーズ:
トークン連結 (6.10.3.3) によってユニバーサル文字名の構文に一致する文字シーケンスが生成された場合、動作は未定義です。
この文字シーケンスは、\u306d\u3053
ユニバーサル文字名を部分文字列として含んでいるため、「ユニバーサル文字名の構文に一致する」可能性があると考えました。また、「一致」とは、連結によって生成されたトークン全体が 1 つのユニバーサル文字名を表すことを意味する可能性があり、そのため、このコードではこの未定義の動作は呼び出されないと考えました。
読むPRE30-C. 連結によってユニバーサル文字名を作成しない、私は、このような連結は許可されているというコメントを見つけました:
禁止されているのは、連結によって新しいUCNを作成することです。
割り当て(\u0001,0401,a,b,4)
UCN を含むものをどこにでも連結するだけで問題ありません。
そしてそれを示すログこの場合のようなコード例(ただし4文字)は次のように置き換えられます別のコード例。
私のコード例では、未定義の動作が呼び出されますか (トークン連結によるユニバーサル文字名の生成によって呼び出されるものに限定されません)? それとも、これは clang のバグですか?
ベストアンサー1
ユニバーサル文字名 (6.4.3) がトークン連結によって生成されないため、コードは、言及されている未定義の動作をトリガーしません。
また、6.10.3.3 によれば、演算子の左側と右側は両方とも##
識別子であり、生成されたトークンも有効な前処理トークン (これも識別子) であるため、##
演算子自体は未定義の動作をトリガーしません。
識別子 (6.4.2、D.1、D.2)、ユニバーサル文字名 (6.4.3) に関する説明を読んだ後、これはトークン連結によって生成された識別子と通常の識別子を異なる方法で処理する clang プリプロセッサのバグに近いものであると確信しました。