PRE30-C. 文字列連結によってユニバーサル文字名を作成しない
C言語規格はユニバーサル文字名をサポートしている。識別子、文字定数、文字列リテラルにおいて、基本文字セットに含まれていない文字をユニバーサル文字名で記載できる。ユニバーサル文字名 \U
nnnnnnnn は、(ISO/IEC10646 で規定されている) 8桁の識別子が nnnnnnnn である文字を示す。同様に、ユニバーサル文字名 \u
nnnn は、4桁の識別子が nnnn (8桁の識別子では 0000
nnnn) となる文字を示す。
C言語規格 [ISO/IEC 9899:2011]、5.1.1.2 のパラグラフ 4 には次のように記載されている。
トークン連結の結果として生成される文字の並びがユニバーサル文字名の構文規則に一致する場合(6.10.3.3)、その動作は未定義である。
未定義動作3 も参照。
絶対に必要である場合を除き、一般に、識別子にユニバーサル文字名を使用するのは避けるべきである。
違反コード
以下の違反コード例では、トークンの連結によってユニバーサル文字名を生成している。
#define assign(uc1, uc2, val) uc1##uc2 = val
void func(void) {
int \u0401;
/* ... */
assign(\u04, 01, 4);
/* ... */
}
処理系固有の詳細
Microsoft Visual Studio 2013では、このコードをコンパイルし実行でき、期待通り変数に4が代入される。
Linux の GCC 4.8.1 では、このコードはコンパイルできない。コンパイラは、assign
マクロの呼出しに含まれるユニバーサル文字の断片に対し、エラーメッセージ "stray '\' in program," を出力する。
適合コード
以下の適合コードではユニバーサル文字名を使用しているが、トークン連結を使って組み立ててはいない。
#define assign(ucn, val) ucn = val
void func(void) {
int \u0401;
/* ... */
assign(\u0401, 4);
/* ... */
}
リスク評価
トークンの連結によりユニバーサル文字名を生成すると、未定義の動作となる。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
PRE30-C |
低 |
低 |
中 |
P2 |
L3 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Axivion Bauhaus Suite |
6.9.0 |
CertC-PRE30 | 実装済み |
CodeSonar |
5.0p0
|
LANG.PREPROC.PASTE LANG.PREPROC.PASTEHASH |
マクロが## 演算子を使用している# 演算子に## が続く |
LDRA tool suite |
9.7.1
|
573 S |
実装済み |
Parasoft C/C++test |
10.4.1 |
CERT_C-PRE30-a | Avoid token concatenation that may produce universal character names |
R2018a |
Universal character name from token concatenation | You create a universal character name by joining tokens with ## operator | |
PRQA QA-C |
9.5 |
0905 |
|
PRQA QA-C++ |
4.3 |
0064, 0080 |
|
参考資料
[ISO/IEC 10646-2003] |
|
[ISO/IEC 9899:2011] | Subclause 5.1.1.2, "Translation Phases" |
翻訳元
これは以下のページを翻訳したものです。
PRE30-C. Do not create a universal character name through concatenation (revision 120)