EXP40-C. 定数オブジェクトを変更しない
C 標準 [ISO/IEC 9899:2011] セクション 6.7.3 のパラグラフ 6 には次のように記載されている。
const
修飾型で定義されたオブジェクトを、非const
修飾型の左辺値を使って変更しようとした場合、その動作は未定義とする。
(C 標準の附属書 J 「未定義の動作」の 64 も参照すること。)
既存のコンパイラ実装によっては、const
修飾型の値の変更を警告なしで許可するものもある。
また、const
修飾をキャストではずすと、const
修飾型の値を警告なしで容易に変更できることになるため、const
修飾をキャストではずさないことも推奨される(「EXP05-C. const 修飾をキャストではずさない」参照)。
違反コード
C 標準のセクション 6.5.16.1 から抜粋した以下のコード例は、きちんと書かれているが定数値を変更できるためルールに違反している。
char const **cpp; char *cp; char const c = 'A'; cpp = &cp; /* 制約違反 */ *cpp = &c; /* 正しい */ *cp = 'B'; /* 正しい */
最初の代入は安全ではない。なぜなら、その後で正しいコードによって const
オブジェクト c
の値を変更できるからである。
違反コード(文字列リテラルの変更)
上記の例と同様、以下のコード例はきちんと書かれているが、const 修飾をキャストではずした後 const オブジェクトを変更しているため、ルールに違反している。Linux/x64 システム上でこのプログラムをコンパイルした場合、厳しい警告レベルでも警告は発行されないが、生成された実行プログラムは実行時に SIGSEGV
により失敗する。
const char s[] = "foo"; int main() { *(char*)s = '\0'; }
処理系固有の詳細
cpp
、cp
、c
が自動(スタック)変数として宣言された場合、上記のコードは、Microsoft Visual C++ .NET (2003) および MS Visual Studio 2005 では警告なしでコンパイルされる。どちらの場合も、生成されるプログラムはc
の値を変更する。MS Visual Studio 2008 はエラーメッセージを表示する。GCC コンパイラのバージョン 3.2.2 は、警告を出すがコンパイルは行う。生成されるプログラムは c
の値を変更する。
cpp
、cp
、c
が静的記憶域期間で宣言された場合、このプログラムは MS Visual Studio と GCC 3.2.2 のどちらの場合も異常終了する。
適合コード
このコード例の適合コードは、プログラマの意図によって異なる。c
の値を変更することを意図している場合は、c を定数として宣言してはならない。c
の値を変更することを意図していない場合は、これを変更するような違反コードを書かないこと。
リスク評価
非 const の参照を通じて const オブジェクトを変更すると、未定義の動作が引き起こされる。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
EXP40-C |
低 |
低 |
中 |
P2 |
L3 |
参考資料
[ISO/IEC 9899:2011] | Section 6.7.3, "Type Qualifiers" |
翻訳元
これは以下のページを翻訳したものです。
EXP40-C. Do not modify constant objects (revision 57)