MISRA-CとはC言語のためのコーディング・ガイドラインです。MISRA-Cは、より安全なC言語サブセットとも言えます。MISRA-Cの遵守はシステムの安全性を高めます。
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
指針 | 1.1 | 必要 | プログラムの出力が依存する処理系定義の動作は、文書化され、理解されなければならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
指針 | 2.1 | 必要 | すべてのソースファイルは、コンパイルエラーなしでコンパイルしなければならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
指針 | 3.1 | 必要 | すべてのコードは文書化された要件へ追跡可能でなければならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
指針 | 4.1 | 必要 | 実行時の障害は最小限に抑えられなければならない (補足) |
指針 | 4.2 | 推奨 | アセンブリ言語のすべての使用は文書化されなければならない |
指針 | 4.3 | 必要 | アセンブリ言語は、カプセル化され、隔離されなければならない |
指針 | 4.4 | 推奨 | コードの一部を「コメントアウト」してはならない |
指針 | 4.5 | 推奨 | 可視性が重複して、同じ名前空間にある識別子は、表記上明白でなければならない (補足) |
指針 | 4.6 | 推奨 | 基本的な数値型の代わりに、サイズと符号の有無を示すtypedefを使用しなければならない |
指針 | 4.7 | 必要 | 関数がエラー情報を返す場合は、そのエラー情報を判定しなければならない |
指針 | 4.8 | 推奨 | 構造体や共用体へのポインタが翻訳単位内で逆参照されることがない場合、オブジェクトの実装は隠されなければならない |
指針 | 4.9 | 推奨 | 関数形式マクロの代わりに、互換性のある関数を使用しなければならない |
指針 | 4.10 | 必要 | ヘッダファイルの内容が複数回インクルードされないように注意しなければならない |
指針 | 4.11 | 必要 | ライブラリ関数に渡す値の妥当性を確認しなければならない |
指針 | 4.12 | 必要 | 動的なメモリ割り当てを使用してはならない |
指針 | 4.13 | 推奨 | リソースに対する操作を提供するように設計された関数は、適切な順序で呼び出さなければならない (補足) |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 1.1 | 必要 | プログラムは標準Cの構文と制約の違反が含まれていないものとし、処理系の翻訳限界を超えてはならない |
ルール | 1.2 | 推奨 | 言語拡張を使用してはいけない (補足) |
ルール | 1.3 | 必要 | 未定義の動作またはクリティカルな未規定の動作の発生があってはならない (補足) |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 2.1 | 必要 | プロジェクトは到達不能なコードを含んではならない |
ルール | 2.2 | 必要 | デッドコードがあってはならない |
ルール | 2.3 | 推奨 | プロジェクトは未使用の型宣言を含んではならない |
ルール | 2.4 | 推奨 | プロジェクトは未使用のタグ宣言を含んではならない |
ルール | 2.5 | 推奨 | プロジェクトは未使用のマクロ宣言を含んではならない |
ルール | 2.6 | 推奨 | プロジェクトは未使用のラベル宣言を含んではならない |
ルール | 2.7 | 推奨 | 関数内に未使用のパラメータがあってはならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 3.1 | 必要 | 「/*」や「//」という文字の並びをコメント内で使用してはならない |
ルール | 3.2 | 必要 | ラインスプライシングは//コメントで使用してはならない (補足) |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 4.1 | 必要 | 8進と16進の逆斜線表記は終了させなければならない |
ルール | 4.2 | 推奨 | 3文字表記を使用してはならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 5.1 | 必要 | 外部識別子は異なったものにしなければならない |
ルール | 5.2 | 必要 | 同じスコープと名前空間で宣言された識別子は異なったものにしなければならない |
ルール | 5.3 | 必要 | 内側のスコープで宣言された識別子は、外側のスコープで宣言された識別子を隠してはならない |
ルール | 5.4 | 必要 | マクロ識別子は異なったものにしなければならない |
ルール | 5.5 | 必要 | 識別子はマクロ名とは異なったものにしなければならない |
ルール | 5.6 | 必要 | typedef名は一意の識別子でなければならない |
ルール | 5.7 | 必要 | tag名は一意の識別子でなければならない |
ルール | 5.8 | 必要 | 外部リンケージを持つオブジェクトや関数を定義する識別子は一意でなければならない |
ルール | 5.9 | 推奨 | 内部リンケージを持つオブジェクトや関数を定義する識別子が一意でなければならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 6.1 | 必要 | ビットフィールドは適切な型で宣言されなければならない (補足) |
ルール | 6.2 | 必要 | ビットフィールドで名付けられたシングルビットは符号付きの型であってはならない (補足) |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 7.1 | 必要 | 8進定数を使用してはならない |
ルール | 7.2 | 必要 | 符号なしの型で表現されているすべての整数定数には「u」または「U」接尾語を適用しなければならない |
ルール | 7.3 | 必要 | 小文字の "l"はリテラルの接尾語に使用してはならない |
ルール | 7.4 | 必要 | オブジェクトの型が「const修飾文字へのポインタ」でない限り、文字列リテラルをオブジェクトに代入してはならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 8.1 | 必要 | 型は明示的に指定されなければならない |
ルール | 8.2 | 必要 | 関数型は名前付きパラメータを持つプロトタイプの形式でなければならない |
ルール | 8.3 | 必要 | オブジェクトまたは関数のすべての宣言は、同じ名前と型修飾子を使用しなければならない |
ルール | 8.4 | 必要 | 外部リンケージを持つオブジェクトや関数が定義される場合、その適合する宣言は可視でなければならない |
ルール | 8.5 | 必要 | 外部オブジェクトまたは関数は1つだけの生存で一度だけ宣言されなければならない |
ルール | 8.6 | 必要 | 外部リンケージを持つ識別子は、1つの外部定義を持たなければならない |
ルール | 8.7 | 推奨 | 翻訳単位内での参照がただ1つである場合、関数やオブジェクトは外部リンケージを使用して定義してはいけない |
ルール | 8.8 | 必要 | 静的記憶クラス指定子は、内部リンケージを持つオブジェクトおよび関数のすべての宣言で使用されなければならない |
ルール | 8.9 | 推奨 | 識別子が単一の関数内にのみ出現する場合、そのオブジェクトはブロックスコープで定義されなければならない |
ルール | 8.10 | 必要 | インライン関数は、静的記憶域クラスを使用して宣言されなければならない (補足) |
ルール | 8.11 | 推奨 | 外部リンケージを持つ配列を宣言する場合、その大きさは明示的に指定されなければならない |
ルール | 8.12 | 必要 | 列挙子リスト内では、暗黙的に指定された列挙定数の値は一意でなければならない |
ルール | 8.13 | 推奨 | ポインタは可能な限りconst修飾型を指さなければならない |
ルール | 8.14 | 必要 | restrict型修飾子を使用してはならない (補足) |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 9.1 | 義務 | 自動記憶域期間を持つオブジェクトの値を値が設定される前に読んではいけない |
ルール | 9.2 | 必要 | 集成体または共用体の初期化子は波括弧で囲まれなければならない |
ルール | 9.3 | 必要 | 配列は部分的に初期化してはならない |
ルール | 9.4 | 必要 | オブジェクトの要素は複数回初期化されてはならない |
ルール | 9.5 | 必要 | 指定された初期化子が配列オブジェクトの初期化に使用されている場合、配列のサイズは明示的に指定されなければならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 10.1 | 必要 | オペランドが不適切な実質的な型であってはならない |
ルール | 10.2 | 必要 | 実質的に文字型の式は、加算と減算操作で不適切に使用してはならない |
ルール | 10.3 | 必要 | 式の値はより狭い実質的な型または異なる実質的な型分類でオブジェクトに代入してはならない |
ルール | 10.4 | 必要 | 通常の算術変換が実行される演算子の両方のオペランドは同じ実質的な型分類を持たなければならない |
ルール | 10.5 | 推奨 | 式の値は不適切な実質的な型にキャストしてはならない |
ルール | 10.6 | 必要 | 複合式の値を、より広い実質的な型のオブジェクトに代入してはならない |
ルール | 10.7 | 必要 | 複合式が通常の算術変換が実行される演算子の1つのオペランドとして使用されている場合、もう一方のオペランドは、より広い実質的な型を持ってはいけない |
ルール | 10.8 | 必要 | 複合式の値は異なる実質的な型分類やより広い実質的な型にキャストしてはならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 11.1 | 必要 | 変換は関数へのポインタと任意の他の型との間で行われてはならない |
ルール | 11.2 | 必要 | 変換は不完全な型へのポインタと任意の他の型との間で行われてはならない |
ルール | 11.3 | 必要 | キャストはオブジェクト型へのポインタ型と別のオブジェクト型へのポインタとの間で行われてはならない |
ルール | 11.4 | 推奨 | 変換はオブジェクトへのポインタと整数型との間で行われてはいけない |
ルール | 11.5 | 推奨 | 変換はvoidへのポインタからオブジェクトへのポインタに行われてはいけない |
ルール | 11.6 | 必要 | キャストはvoidへのポインタと算術型との間で行われてはならない |
ルール | 11.7 | 必要 | キャストはオブジェクトへのポインタと非整数算術型との間で行われてはならない |
ルール | 11.8 | 必要 | キャストはポインタによって指さされた型から任意のconstまたはvolatile修飾を削除してはならない |
ルール | 11.9 | 必要 | マクロNULLは整数ヌルポインタ定数の形式のみ許されなければならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 12.1 | 推奨 | 式の中の演算子の優先順位は明白でなければならない |
ルール | 12.2 | 必要 | シフト演算子の右側のオペランドは、0以上で、左側のオペランドの実質的な型のビット幅未満でなければならない |
ルール | 12.3 | 推奨 | コンマ演算子を使用してはならない |
ルール | 12.4 | 推奨 | 定数式の評価は、符号なし整数のラップアラウンドを引き起こしてはならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 13.1 | 必要 | 初期化リストは永続的な副作用を含んではならない (補足) |
ルール | 13.2 | 必要 | 式の値とその永続的な副作用は、すべての許可された評価順で同じでなければならない |
ルール | 13.3 | 推奨 | インクリメントまたはデクリメント演算子を含む完全な式はインクリメントまたはデクリメント演算子に起因するもの以外、他の潜在的な副作用があってはならない |
ルール | 13.4 | 推奨 | 代入演算子の結果を使用してはならない |
ルール | 13.5 | 必要 | &&や||の論理演算子の右側のオペランドは、永続的な副作用を含んではならない |
ルール | 13.6 | 義務 | sizeof演算子のオペランドは潜在的な副作用を持っている任意の式を含んではならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 14.1 | 必要 | ループカウンタは、実質的に浮動小数点型を持ってはいけない |
ルール | 14.2 | 必要 | forループは適正に定義されなければならない |
ルール | 14.3 | 必要 | 制御式は不変であってはならない |
ルール | 14.4 | 必要 | if文の制御式と繰り返し文の制御式は、実質的にBoolean型を持たなければならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 15.1 | 推奨 | goto文を使用してはならない |
ルール | 15.2 | 必要 | goto文は、同じ関数のより後ろで宣言されたラベルにジャンプしなければならない |
ルール | 15.3 | 必要 | goto文によって参照されるラベルは、同じブロック内、またはgoto文を囲む任意のブロック内で宣言されなければならない |
ルール | 15.4 | 推奨 | 繰り返し文を終了するために使用されるブレーク文またはgoto文は1個以下でなければならない |
ルール | 15.5 | 推奨 | 関数は、その最後に1つだけの出口を持たなけらばならない |
ルール | 15.6 | 必要 | 反復文や選択文の本体は、複合文でなければならない |
ルール | 15.7 | 必要 | すべてのif ... else if構文は、else文で終了しなければならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 16.1 | 必要 | すべてのswitch文は適正に定義されなければならない |
ルール | 16.2 | 必要 | スイッチのラベルは、それを直接内包している複合文がswitch文の本体である場合にのみ使用されなければならない |
ルール | 16.3 | 必要 | 無条件のbreak文で、すべてのスイッチ節を終了しなければならない |
ルール | 16.4 | 必要 | すべてのswitch文は、デフォルトのラベルをもたなければならない |
ルール | 16.5 | 必要 | デフォルトのラベルは、switch文の最初または最後いずれかのスイッチのラベルとしなければならない |
ルール | 16.6 | 必要 | すべてのswitch文は、少なくとも2つのスイッチ節を持たなければならない |
ルール | 16.7 | 必要 | スイッチ式は実質的にブール型を持ってはいけない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 17.1 | 必要 | <stdarg.h>の特色を使用してはならない (補足) |
ルール | 17.2 | 必要 | 関数は、直接的または間接的に、自分自身を呼び出しはいけない |
ルール | 17.3 | 義務 | 関数を暗黙的に宣言してはならない |
ルール | 17.4 | 義務 | void以外の戻り値の型を持つ関数からのすべての出口は式を伴った明示的なreturn文を持たなければならない |
ルール | 17.5 | 推奨 | 配列型を持つように宣言されたパラメータに対応する関数の引数は、要素の適切な数を持たなければならない |
ルール | 17.6 | 義務 | 配列パラメータの宣言は、[ ]の間に静的キーワードを含んではならない (補足) |
ルール | 17.7 | 必要 | void以外の戻り値の型を持つ関数が返す値は使用されなければならない |
ルール | 17.8 | 推奨 | 関数パラメータを変更してはいけない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 18.1 | 必要 | ポインタオペランドの算術に起因するポインタはそのポインタのオペランドと同じ配列の要素を処理しなければならない |
ルール | 18.2 | 必要 | ポインタ間の減算は、同じ配列の要素を扱うポインタにのみ適用されなければならない |
ルール | 18.3 | 必要 | 関係演算子>、>=、<と<=は、それらが同じオブジェクト内を指している場合を除いて、ポインタ型のオブジェクトに適用してはならない |
ルール | 18.4 | 推奨 | +、 - 、+=と - =演算子は、ポインタ型の式に適用してはいけない |
ルール | 18.5 | 推奨 | 2段階を超える入れ子のポインタを宣言してはいけない |
ルール | 18.6 | 必要 | 自動記憶域を持つオブジェクトのアドレスを、そのオブジェクトが存在しなくなった後も存在する別のオブジェクトにコピーしてはならない |
ルール | 18.7 | 必要 | フレキシブル配列メンバを宣言してはいけない |
ルール | 18.8 | 必要 | 可変長配列型を使用してはならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 19.1 | 義務 | オブジェクトは、重複オブジェクトに代入あるいはコピーされてはならない (補足) |
ルール | 19.2 | 推奨 | unionキーワードを使用してはならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 20.1 | 推奨 | #include指令に対しては、他の前処理指令やコメントのみが先行しうる |
ルール | 20.2 | 必要 | 「'」、「"」または「\」文字、「/*」または「//」文字列がヘッダファイル名に存在してはならない |
ルール | 20.3 | 必要 | #include指令の後には<filename>文字列または"filename"文字列のどちらかが続かなくてはならない |
ルール | 20.4 | 必要 | マクロは、キーワードと同じ名前で定義してはいけない |
ルール | 20.5 | 推奨 | #undefを使用してはならない |
ルール | 20.6 | 必要 | 前処理指令のように見える字句は、マクロ引数内に存在してはならない |
ルール | 20.7 | 必要 | マクロパラメータの展開の結果生じる式は、括弧で囲まれなければならない |
ルール | 20.8 | 必要 | #if前処理指令または#elif前処理指令の制御式は、0または1に評価されなければならない |
ルール | 20.9 | 必要 | #if前処理指令または#elif前処理指令の制御式で使用されるすべての識別子は、評価の前に#defineされていなければならない |
ルール | 20.10 | 推奨 | #前処理演算子と##前処理演算子を使用してはならない |
ルール | 20.11 | 必要 | #演算子の直後に続くマクロパラメータの直後に##演算子を続けてはいけない |
ルール | 20.12 | 必要 | さらに先のマクロ置換の変換そのものである、#演算子または##演算子のオペランドとして使用されるマクロパラメータは、これらの演算子のオペランドとして使用されなければならない |
ルール | 20.13 | 必要 | その最初の字句が#である行は、有効な前処理指令でなければならない |
ルール | 20.14 | 必要 | すべての#else、#elif と#endif 前処理指令は、関連する#if、#ifdef、または#ifndef指令と同じファイルになければならない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 21.1 | 必要 | 予約済み識別子や予約済みマクロ名に対して#defineや#undefを使用してはならない |
ルール | 21.2 | 必要 | 予約済み識別子またはマクロ名を宣言してはならない |
ルール | 21.3 | 必要 | <stdlib.h>のメモリ割り当てと解放の機能を使用してはならない |
ルール | 21.4 | 必要 | 標準ヘッダファイル<setjmp.h>を使用してはならない |
ルール | 21.5 | 必要 | 標準ヘッダファイル<signal.h>を使用してはならない |
ルール | 21.6 | 必要 | 標準ライブラリの入力/出力の機能を使用してはならない |
ルール | 21.7 | 必要 | <stdlib.h>のatof関数、atoi関数、atol関数とatoll関数を使用してはならない |
ルール | 21.8 | 必要 | <stdlib.h>のライブラリ関数 abort、exit、getenv そしてsystemを使用してはならない |
ルール | 21.9 | 必要 | <stdlib.h>のライブラリ関数 bsearchとqsortを使用してはならない (補足) |
ルール | 21.10 | 必要 | 標準ライブラリのtimeとdate関数を使用してはいけない (補足) |
ルール | 21.11 | 必要 | 標準ヘッダファイル<tgmath.h>を使用してはならない (補足) |
ルール | 21.12 | 推奨 | <fenv.h>の例外処理機能を使用してはいけない |
分類 | 項番 | カテゴリ | ガイドライン |
---|---|---|---|
ルール | 22.1 | 必要 | 標準ライブラリ関数を用いて動的に得られたすべてのリソースは、明示的に解放されなければならない |
ルール | 22.2 | 義務 | メモリブロックは、それが標準ライブラリ関数を用いて割り当てられていた場合にのみ、解放されなければならない |
ルール | 22.3 | 必要 | 同じファイルを、同時に異なるストリームで、読取りアクセスと書込みアクセスのためにオープンしてはいけない |
ルール | 22.4 | 義務 | 読み取り専用として開かれたストリームに書き込もうとしてはいけない |
ルール | 22.5 | 義務 | FILEオブジェクトへのポインタを逆参照してはならない |
ルール | 22.6 | 義務 | 関連したストリームが閉じられた後に、FILEへのポインタの値を使用してはならない |
MISRA-CとはC言語のためのコーディング・ガイドラインです。ヨーロッパの団体であるMISRAが制定しています。対象は、C言語で記述されたクリティカルなシステム(主に組込み系)です。クリティカルなシステムでは、高い安全性と信頼性が要求されます。また移植性も重要です。MISRA-Cの目的はこれらを確保することです。クリティカルなシステム向けのガイドラインとなっていますが、安全性がさほど求められない分野においてもよく使用されています。ソフトウェアの品質向上のためです。ヨーロッパで制定されたガイドラインですが、日本や北米でも広く普及しています。
MISRA-Cを制定しているMISRAとはどのような団体でしょうか? MISRAは Motor Industry Software Reliability Association の略です。直訳すると「自動車産業ソフトウェア信頼協会」になるでしょうか。自動車メーカー、部品メーカー、エンジニアリングコンサルタントが連携した団体です。そのミッションは「安全で信頼性の高い自動車システム用ソフトウェア作成のための自動車業界への支援を提供する」こととされています。
MISRAには2014年現在下記メンバが所属しています。
公式サイトによると、MISRAの発足は1990年代初頭だそうです。イギリス政府の「SafeIT」プログラム内のプロジェクトとして発足しました。目的は自動車組込みシステム用ソフトウェア作成のためのガイドライン制定です。1994年11月に車両ベースのソフトウェアのための開発ガイドライン(Development Guidelines for Vehicle Based Software)を公開。このドキュメントは、新しいIEC 61508規格(電気・電子・プログラマブル電子の機能安全に関する国際規格)への初めての自動車産業の解釈でもありました。
「SafeIT」からの資金供給が終わってからも、MISRAは継続されました。その最初の成果がMISRA-Cとなります。MISRA-Cはフォード社とローバー社が作成したC言語サブセットをベースに作成されました。以来、MISRA-Cは、安全関連産業においての、C言語組込みシステムのデファクトスタンダードを目指して継続されています。
MISRA-Cの初版は1998年に発表されました。タイトルは「Guidelines for the use of the C language in vehicle based software」(自動車用ソフトウェアでC言語を利用するための手引き)。通称、MISRA-C:1998と表現されています。ガイドラインには17に区分された127件のルールがあります。そのうち必要ルールは93、推奨ルールは34となっています。解説書としては、日本規格協会から『組込み開発者におくるMISRA-C−組込みプログラミングの高信頼化ガイド』(ISBN 978-4542503342)が出版されています。
2004年10月13日には第2版が公開されました。タイトルは「Guidelines for the use of the C language in critical systems」(クリティカルシステムでC言語を利用するための手引き)です。こちらは通称、MISRA-C:2004と呼ばれています。MISRA-C:1998の運用や研究の結果が反映されています。対象が自動車用ソフトウェアから全ての組込みソフトウェアへと拡大されていることも特徴です。21に区分されたルールが141件あります。そのうち必須ルールは121、推奨ルールは20です。翻訳が公益社団法人自動車技術会(JASO)から『自動車用C言語利用のガイドライン(第2版)』(文献番号tp-01002-06)として出版されています。解説書としては、日本規格協会から出版された『組込み開発者におくるMISRA-C:2004−C言語利用の高信頼化ガイド』(ISBN 978-4542503465)があります。
MISRA-Cの第3版は2013年3月18日に発行されました。通称MISRA-C:2012です。第3版はC99対応のため改訂です。内容の整理や充実化、定義の明確化もなされています。26に区分されており、指針が16件、ルールが143件となっています。MISRA-C:2012から「指針」が加えられています。指針・ルールのうち義務は10、必要は111、推奨は39です。2014年現在、出版された翻訳および解説書はありません。
C言語は広く普及しているプログラミング言語です。ハードウェアよりの低水準な処理も記述可能でとても便利です。反面、発見の難しい不具合も多く発生します。コンパイル時や実行時のチェック機能が脆弱などの短所もあります。便利ではあるが安全性に問題ありと判断できます。安全性はMISRA-Cのようなコーディングガイドラインを守ることによりある程度保証可能です。より安全なC言語サブセットを定義するMISRA-Cは完成度も高く、C言語利用者にとって重要なガイドラインと言えるでしょう。
MISRA-C:2012 ルール一覧 では分かりにくい指針・ルールについて下記に補足します。
具体的には、実行時エラーが発生する可能性がある場所に動的なチェックを追加するということです。チェックを検討すべき分野は、オーバフローや0除算などの算術エラー、ポインタ演算、配列の境界エラー、関数のパラメータ、ポインタの参照、動的メモリーの割当などです。また、設計標準、テスト計画、静的解析設定ファイル、コードレビューのチェックリストなど、実行時の障害を最小化するための技術文書を準備しておく必要もあるとされています。
「可視性が重複した識別子」とは「使用可能な識別子」という理解でよいでしょう。また、C言語には名前空間は4種類あります。「ラベル名」「構造体,共用体及び列挙体のタグ」「構造体又は共用体のメンバ」「その他のすべての識別子」です。「表記上明白」とは、少なくともラテンアルファベットに関しては「以下の変化で識別子が同じにならない」ということです。
この指針は「リソースを扱う際には、その操作関数を適切な順序で呼び出す必要がある」という意味です。リソースに対する操作を提供する関数群は、だいたい次のような3つの種類に分けられます。
そのため、一連の関数は適切な順序でコールされる必要があるということです。
言語拡張とは、各コンパイラの設計者等によって独自に決められた、標準の仕様にはない拡張された言語仕様のことです。
未定義の動作とは、簡単にいうと異常なプログラムの動作のことであり、その動作が規格上定義されていないものです。例としては、整数演算のオーバフローに対する動作などがあります。コンパイル時に指摘されることもありますが、実行時にプログラムの異常を検出せず、予測不能な結果を生じることもあります。そのため厳重な注意が必要です。また、未規定の動作とは、プログラムの動作として2つ以上の可能性があり、どれが実行されるかは規定されないというものです。例えば、関数の実引数の評価順序などです。
ラインスプライシングは「\」文字の後に改行文字が続くと発生します。//コメントでラインスプライシングを利用すると次の行までコメントになります。その結果、可読性が低下し、思わぬ不具合を招く可能性が高くなります。
適切なビットフィールド型は次のように定められています。C90においては、unsigned int型またはsigned int型。C99においては、(1)unsigned int型またはsigned int型、(2)それ以外の、処理系によって許可された、明示的な符号付き、または明示的な符号なし整数型、(3)_Bool型。
このルールは、符号付きの型のビットフィールドをビット幅1として宣言することを禁止するルールです。符号付きの型で宣言されたビットフィールドのビット幅は最低でも2ビット必要です。値の他に符号を表す1ビットが必要となるためです。
インライン関数が、外部リンケージで宣言されていて、同じ翻訳単位で定義されていない場合、その動作は未定義です。外部リンケージで宣言されたインライン関数の呼び出しは、関数の外部定義を呼び出すかもしれませんし、インライン定義を使用するかもしれません。この場合、呼び出された関数の動作に変わりはありませんが、実行タイミングには影響があります。そのため、リアルタイム・プログラムにおいては影響が出てしまう可能性があります。異なる翻訳単位で同じインライン関数を使用する場合は、インライン関数をヘッダファイルで定義するとよいでしょう。
restrict修飾された複数のポインタは、それぞれが同じオブジェクトを指していないことを意味します。ristrictはコンパイラの最適化を助けるための型修飾子です。全てのrestrict修飾子を削除してもプログラムの意味は変わりません。restrict修飾子を使用するには、プログラマが複数のポインタによって操作されるメモリ領域が重ならないことを保証する必要があります。restrictの誤用は、期待どおりには動作しないコードの生成につながります。そのため、MISRA-C:2012は、restrict型修飾子の使用を禁止しています。
このルールは、集成体型の自動オブジェクトの初期化子に実行時に評価される式を含む場合、その式の評価で副作用を発生させてはいけないというルールです。初期化リスト内の式の評価中に発生する副作用の順序は定義されておらず、初期化の動作が予測不明となるからです。
副作用とは、式の評価に際して付随的に実行環境の状態に変化をもたらす効果のことです。ボラタイルオブジェクトへのアクセス、オブジェクトの変更、ファイルの変更、そしてこれらのいずれかの操作を行う関数が副作用となります。また、集成体型とは配列型と構造体型の総称です。集成体型には共用体型は含まれません。
標準規格はstdarg.hに関連した未定義の動作の例を多く挙げています。そのためMISRA-C:2012は、va_list、va_arg、va_start、va_end、va_copyの使用を禁止しています。
C99では配列パラメータでstaticキーワードを使うことにより、渡す配列の最小要素数を保証することができます。
void func(int ary[static 10])
{
// 略
}
上記の例では、配列aryは最低10個の要素を含む必要があります。この仕様はコンパイラの最適化を助けます。しかし、指定した最小要素数より要素数が少ない配列をパラメータとして渡してしまった場合、その時の動作は未定義です。MISRA-C:2012は、コードの最適化よりも安全性を重視して、配列パラメータ宣言の[ ]内でのstaticキーワード使用を禁止しています。
メモリ上で一部が重なり合っている2つのオブジェクトがある状態で、一方のオブジェクトをもう一方のオブジェクトに代入した時の動作は未定義です。また、memmove以外のライブラリ関数を使って上記のような重なり合うオブジェクト間でコピーを行った時の動作も未定義です。そのためルール19.1が制定されています。
このルールには、例外が2つあると記されています。
bsearchおよびqsortからコールされる比較関数が対象となっている配列の内容を変更した場合、その動作は未定義です。また、比較関数が首尾一貫した比較結果を返さない場合の動作も未定義です。そのため、ルール21.9が存在します。
bsearchに渡される配列内にキーと等しいと判定される要素が2つある場合、bsearchがどちらを返すかは未規定の動作です。また、qsortに渡される配列内に等しいと判定される要素が2つある時、整列された配列内でのそれらの順序は未規定です。これらの未規定の動作については、比較関数で0を返さないようにすれば回避できます。例えば、要素が等しいと判断される場合は初期状態の配列の格納順で大小を決めるなどすれば、比較関数で0を返さずに済みます。
time.hにより提供される時刻や日付の関数は便利です。しかし、これらは未規定の動作や未定義の動作、処理系定義の動作を含みます。そのため、MISRA-C:2012はこれらの使用を禁止しています。
time.hではありませんが、wchar.hのwcsftime関数の使用も禁止されています。
tgmath.hで定義される型総称マクロを誤って使用すると、未定義の動作が発生します。そのため、MISRA-C:2012はtgmath.hの使用を禁止しています。