MISRA-C:2004 ガイドブック
最終更新日 2008年1月26日

MISRA-C:2004 ガイドブック の概要

本書は、2004年5月に発刊された『組込み開発者におけるMISRA-C 組込みプログラミングの高信頼化ガイド』の後継となる、MISRA-C:2004対応の解説書です。

※MISRA-C (Guidelines for the use of C language in critical systems)

MISRA-C:1998は、もともと車載用ソフトウェアを対象としたプログラミングガイドラインでしたが、その有益性から日本、欧州、北米の自動車業界、航空・宇宙、医療その他多くの分野でも採用されました。その研究・運用結果からフィードバックを盛り込み、MISRA-C:2004では、すべての組込みソフトウェア向けに対象を広げています。
本書では、ソフトウェア開発者がMISRA-Cを適用するにあたって、MISRA-C:2004の原書を見ただけでは理解しづらく、注意が必要だと思われる事項についての解説をしています。

ISBN: 4542503461 日本規格協会 ¥4,095 (税込) MISRA-C研究会 (編さん)
お近くの書店かインターネット書店で注文してください。


主要目次

1. はじめに
2. 本書の位置付け
2.1 C言語とMISRA-Cを取り巻く背景
2.2 検討の前提
2.3 解説書の活用方法
2.4 第1版(MISRA-C:1998)と第2版(MISRA-C:2004)の違い
3. 本書の構成
4. MISRA-C適用における注意事項
4.1 C90
4.2 メトリクス
4.3 必要ルールと推奨ルール
4.4 C90の附属書G
4.5 MISRA-Cの導入(adopting)
5. 本書で使用している用語
5.1 副作用と副作用完了点
5.2 ビットフィールド
5.3 ブール式(boolen expressions)
5.4 switch式
5.5 潜在型(Underlying type)
5.6 平衡化(balancing)
5.7 ラップアラウンド(wrap around)
5.8 符号属性(signedness)
5.9 複合式(Complex expression)
6. ルール
6.1 環境
6.2 言語拡張
6.3 文書化
6.4 文字集合
6.5 識別子
6.6
6.7 定数
6.8 宣言及び定義
6.9 初期化
6.10 算術型変換
6.11 ポインタ型の変換
6.12
6.13 制御文の式
6.14 制御フロー
6.15 switch文
6.16 関数
6.17 ポインタ及び配列
6.18 構造体及び共用体
6.19 前処理指令
6.20 標準ライブラリ
6.21 実行時誤り
7. 参考文献
あとがき  
付録 A. ルール一覧
付録 B. MISRA-C:1998 と MISRA-C:2004 のルールマッピング
付録 C. MISRA-C:1998 − 廃止されたルールマッピング
付録 D. ISO標準との相互参照表
付録 E. Koeningのセクション番号と英文ページ番号との相互参照表
付録 F. 附属書G(参考)可搬性

内容についての疑問点や不明点については sessame-misrac-query@blues.se.uec.ac.jp までご連絡ください


組込み開発者におくるMISRA-C:2004』 正誤表

該当個所 内容
1刷/ P.54
ルール2.1
【サンプル】
例4
if( u16_arg == 0U ) /* Cコードが存在する */
 {
 #pragma asm /* 非適合: Cコードと 〜省略〜 */
  /* アセンブリ言語で記述 */
 #pragma endasm
 }
}
if( u16_arg == 0U ) /* Cコードが存在する */
{
 #pragma asm /* 非適合: Cコードと 〜省略〜 */
  /* アセンブリ言語で記述 */
 #pragma endasm
}
if文の次の "{" の位置を修正
"#pragma emdasm"の直後の "}" を削除

1刷/ P.119
ルール8.9
【サンプル】
例1 補足2
u16_var2の定義
u16_var2の仮定義
定義を仮定義に修正

1刷/ P.120
ルール8.9
【サンプル】
例2 補足2
u16_var2は・・・定義されている
u16_var2は・・・仮定義されている
定義を仮定義に修正

1刷/ P.120
ルール8.9
【備考】
3行目の最後
・・・外部定義と扱われる.
・・・外部定義があるかのように扱われる.
仮定義によって実体が確保されるタイミングは明確に定められておらず,翻訳 単位毎に1つの実体が確保される処理系と,リンク時にプログラム全体で1つだけ の実体が確保される処理系がある. 可搬性を考えると,外部結合のオブジェクトは, 仮定義も定義と同様に,1つの翻訳単位だけで行うことが望ましい.
赤字は修正.青字は追加

1刷/ P.120〜121
ルール8.9
【備考】
補足2
補足2:・・・仮定義がある. しかし,・・・存在することとなる.
補足2:・・・仮定義がある. 処理系によっては,両方とも外部定義として扱われることがある.
「しかし」以降を全置換え

1刷/ P.125
ルール8.11
【備考】
4行目
ブロック有効範囲で内部結合となり
ブロック外の識別子と結合を持たず
説明の誤りを修正

1刷/ P.144
ルール10.2
【解説】
6行目
・符号付き整数型と符号なし整数型の間で暗黙の型変換を行わない.
 
削除

1刷/ P.154
ルール10.5
【サンプル】
9行目
/* 適合: result_16は 0x000a */
/* 適合: result_16は 0x0ffa */
誤記修正

1刷/ P.154
ルール10.5
【サンプル】
10行目
result_16 = (( port << 4) & mode) >> 6;
result_16 = (( port << 9) & mode) >> 6;
誤記修正

1刷/ P.158
ルール11.2
【潜在的問題】
2行目
又はvoidポインタ以外への変換した場合,
又はvoidポインタ以外へ変換した場合,
誤記修正

1刷/ P.195
ルール13.3
[例3]
1行目
<省略> && (f32_var1 >= f32_var1) ) /* 非適合 */
<省略> && (f32_var1 >= f32_var2) ) /* 非適合 */
誤記修正

1刷/ P.201
ルール13.7
[例1]
頁の最下行
<省略> && ( si8_var > 20 ) ) /* 常に偽 */
<省略> && ( s8_var > 20 ) ) /* 常に偽 */
誤記修正

1刷/ P.202
ルール13.7
[例1]
頁の最上行
<省略> || ( si8_var > 5 ) ) /* 常に真 */
<省略> || ( s8_var > 5 ) ) /* 常に真 */
誤記修正

1刷/ P.202
ルール13.7
[例2]
if ( flag == TRUE ) /* ブール演算(!FALSE)の結果は常に真:補足参照 */
{ ・・・ }

補足:定数式内でのブール演算はルール 13.7 に非適合である.
if ( flag == TRUE ) /* 非適合:補足参照 */
{ ・・・ }

補足:== の右辺のオペランド TRUE はマクロ置換で !FALSE となり,値が不変のブール演算であるため非適合となる.
ISO C では,0 以外の値は「真」として扱われるが,!0 の結果は 1 となると規定されている.この条件式は,flag が 1 の場合にだけ真となる.
説明の加筆

1刷/ P.214
ルール14.6
【サンプル】
例3
 if (ary[var1][var2] == 0)
 {
  break; /* 適合:外側のforループに 〜省略〜 */
}
 if (ary[var1][var2] == 0)
 {
  break; /* 適合:外側のforループに 〜省略〜 */
 }
}
break; の次の行に "}" を追加

1刷/ P.224〜P.225
ルール15.2
[例2]
switch文全体
switch (si16_varx)
{
   case 0:
      {
      si16_a = si16_b;
      break;
        /* 適合:case 0の節の複合文(節内で最も外側の{ })はbreak文で終了 */
      }

   case 2:
      {
      if (si16_a == si16_b)
      {
         si16_a = 0;
      }
      else
      {
         si16_a = si16_b;
      }
      break;
        /* 適合:case 2の節の複合文(節内で最も外側の{ })はbreak文で終了 */
   }
default:
   {
   errorflag = 1;
   break;
        /* 適合:default節の複合文(節内で最も外側の{ })はbreak文で終了 */
   }
}
switch (si16_varx)
{
   case 0:
   {
      si16_a = si16_b;
      break;      /* 適合:節の複合文(節内で最も外側の{ })はbreak文で終了 */
   }
   case 1:
   {
      if (si16_a == si16_b)
      {
         si16_a = 0;
         break;   /* 非適合:「真」のときだけ有効(無条件breakでない) */
      }
      else
      {
         si16_a = si16_b;
         break;   /* 非適合:「偽」のときだけ有効(無条件breakでない) */
      }
        /* 非適合:節の複合文はbreak文で終了していない */
   }
   default:
   {
      errorflag = 1;
      break;      /* 適合:節の複合文はbreak文で終了 */
   }
}
段付けの深さをのずれを修正
case 2を削除しcase 1を非適合例として追加
コメントの簡略化

1刷/ P.333
表B-1
最下段
101(必要)
101(推奨)
誤記修正

2刷/ P.21
3.本書の構成
【ルール】の最後に加筆
・・・,ルールそのものではないとした.
・・・,ルールそのものではないとした.
ルール文の最後に[ ]で囲まれたキーワードが記されている場合がある. これは,MISRA-C:2004第5章 5.5.1「参照元文章の略号」に記載された 「略号」であり,以下の参照元文書に対応する.
 [未規定] 未規定の動作(C90付属書 G.1)
 [未定義] 未定義の動作(C90付属書 G.2)
 [処理系定義] 処理系定義の動作(C90付属書 G.3)
 [Koenig] 邦題「C言語の落とし穴」 本書付録E参照
加筆

2刷/ P.85
ルール5.7
【備考】最後から3行目
・・・,識別子の再使用を許すものをルール4.7からの逸脱
・・・,識別子の再使用を許すものをルール5.7からの逸脱
誤記修正。

2刷/ P.100〜101
ルール8.1
【備考】1行目、参考 、[例]の説明およびコードの途中のコメント
C90はK&Rを包括しているため,K&Rスタイルでの関数定義の記述も許される.
ルール8.1は,・・・
・・・
参考:以下のようにK&Rスタイルではプロトタイプ宣言・・・
・・・
[例]関数のプロトタイプ宣言とK&Rスタイルでの関数定義
・・・
int func2(s8_arg1, s8_arg2) /* K&Rスタイルではエラーにならない */
ISO Cは,古い形式といわれる仮引数の識別子並びと宣言子並びを別々に与える関数定義の記述も許される.
ルール8.1は,・・・
・・・
参考:以下のように古い形式の関数定義ではプロトタイプ宣言・・・
・・・
[例]関数のプロトタイプ宣言と古い形式での関数定義
・・・
int func2(s8_arg1, s8_arg2) /* 古い形式ではエラーにならない */
「K&R」を「古い形式」という表現に変更し、「古い形式の関数定義」の説明を加筆した。

2刷/ P.139
ルール10.1
【サンプル】中央付近
  f32_var1 = s16_var1;     /* 非適合:精度,値の損失 */
/* 代入変換(値の代入)*/
  f32_var1 = s16_var1;     /* 非適合:補足4参照 */
/* 代入変換(値の代入)*/
非適合理由を明確にするため修正。

2刷/ P.140
ルール10.1
【サンプル】中央付近
補足4:実際には情報の損失は起こらないが 浮動小数点型への暗黙の型変換である.
補足4:整数型から浮動小数点数型への暗黙の型変換である.
ただし,C90 5.2.4.2.2 にある「浮動小数点数の表 現に関するモデル」に合致する多くのコンパイラでは,仮数部で表現可能な 整数値は,浮動小数点型に変換しても情報損失を起こさない.
非適合理由を明確にするため修正。

2刷/ P.175
ルール12.5
【サンプル】22行目
if ( boo_var1 || bool_var2 || bool_var3 ) /* 適合 */
if ( bool_var1 || bool_var2 || bool_var3 ) /* 適合 */
誤記修正

2刷/ P.180
ルール12.7
【サンプル】例1
uint16_var1 = uint16_var2 & 0xFFU; /* 適合:補足参照 */
uint16_var1 = uint16_var2 & 0xFFU; /* 適合 */
誤記修正

2刷/ P.180
ルール12.7
【サンプル】例2
int16_t int16_var1, int16_var2, int16_var3;

int16_var3 = int16_var2 | int16_var3; /* 非適合:補足参照 */

補足:符号付16ビット型なので,|演算子の結果の値は処理系定義である.
int16_t int16_var2, int16_var3;

int16_var3 = int16_var2 | int16_var3; /* 非適合 */
未使用変数の削除。
「補足」の削除。

2刷/ P.237〜238
ルール16.5
【潜在的問題】
 C90は,K&Rを包括している(*)ため,K&Rスタイルでの関数の宣言又は定義の記述も許される.
 しかし,K&Rスタイルでは,・・・
 ISO Cは,古い形式(*)での関数の宣言又は定義の記述も許される.
 しかし,古い形式では,・・・
「K&R」を「古い形式」に変更。

2刷/ P.237
欄外
(*)C90 6.5.4.3項の制約・・・
  ・・・
 は,K&Rスタイルでの関数の宣言と定義を示している.
 K&Rスタイルでは,・・・

(*)C90 6.5.4.3項の制約・・・
  ・・・
 は,古い形式での関数の宣言と定義を示している.
 古い形式では,・・・

「K&R」を「古い形式」に変更。

2刷/ P.238
ルール16.5
【サンプル】[例1]
[例1]非適合:K&Rスタイルで仮引数をもたない・・・
・・・
・・・
補足:K&Rスタイルで仮引数をもたない・・・

[例1]非適合:古い形式で仮引数をもたない・・・
・・・
・・・
補足:古い形式で仮引数をもたない・・・

「K&R」を「古い形式」に変更。

2刷/ P.239
ルール16.5
【サンプル】[例3]
[例1]非適合:K&Rスタイルで仮引数をもたない・・・
・・・
・・・
補足:K&Rスタイルで仮引数をもたない・・・

[例1]非適合:古い形式で仮引数をもたない・・・
・・・
・・・
補足:古い形式で仮引数をもたない・・・

「K&R」を「古い形式」に変更。

2刷/ P.352
索引 K
K&R    100
  −スタイル   100

koenig  21,340
「K&R」を削除し「koenig」を追加。

2刷/ P.355
索引 か
関数 96,101,106,・・・
・・・
  − 定義 96,236,240
  − の型 96

関数 96,101,106,・・・
・・・
  − 定義 96,236,240
  − 定義の古い形式 100,237,238,239,240
  − の型 96

「定義の古い形式」の索引を追加