SWEST18【演習で学ぶ！】C ⾔語に潜むリスクと、MISRA Cの有効性

MISRA-C研究会
株式会社サニー技研
尾仲© 2016 Sunny Giken Inc. All rights reserved.

洋和

このコードのリスクは何でしょうか？

a = b = 0;
解説は、番組講義の最後に！
解説は、番組の最後に！
© 2016 Sunny Giken Inc. All rights reserved.

-1-イントロダクション（⾃⼰紹介）【⾃⼰紹介】

株式会社 サニー技研に所属
半導体⼯場向け装置の開発などを経て、現在は、⾞載向けソフトウェア開発を担当。MISRA-C研究会には、第3期から参加。

【MISRA-C研究会とは】「MISRA C」を正しく理解して、実⽤的な形でまとめて⽇本の組み込み業界に紹介するグループ
参加メンバーは、規格の専⾨家、コンパイラ開発者(⾔語規格の専⾨家)、静的開発ツール開発者、組み込みソフト開発者 など【歴史】① 第1期（2002-2004） 対象：MISRA-C:1998
取り纏め：東陽テクニカ、参加23社/28名② 第2期（2004-2006） 対象：MISRA-C:2004
取り纏め：東陽テクニカ、参加31社/35名③ 第3期（2013-2016） 対象：MISRA C:2012
取り纏め：名古屋市⼯業研究所、参加16社/18名© 2016 Sunny Giken Inc. All rights reserved.

-2-推敲中イントロダクション（⽬的）【⽬的】

本講義では、⾮常にシンプルなコードを参考にして、Ｃ⾔語（プログラミング⾔語）の持つ奥の深さ、リスク、おもしろさを感じ取って頂き、どうすれば、楽しくかつ安全なコーディングができるかなどを皆さんが考えるきっかけになればと願っています。
そして、それらのC⾔語のリスクをMISRA Cでどのように防いでいくかを、実感いただきたいと考えております。

【依頼事項】

問題を出しますので、正解と思う時に⼿を挙げて下さい！

© 2016 Sunny Giken Inc. All rights reserved.

-3-コード事例１ （問題）下記の範囲は？

A) char①-128~127 ②0~255 ③その他

B) short①-32768~32767 ②0~65535 ③その他

C) unsigned int①0~65535© 2016 Sunny Giken Inc. All rights reserved.

②0~4294967295-4-③その他

コード事例１ （回答）A) char0 〜 255 or -128 〜 127

charは、処理系により符号ありなしが異なるB) short-32768 〜 32767

C) unsigned int

0 〜 65535 or0 〜 4294967295

int, unsigned intは、処理系によりサイズが異なる

処理系により範囲が異なる！
© 2016 Sunny Giken Inc. All rights reserved.

-5-コード事例１ （解説）< MISRA C:2012で検出 >Directive 4.6(推奨)
基本的な数値型の代わりに、サイズと符合属性を⽰す
typedefを⽤いるべきである。
処理系により符号やサイズが異なるchar、intなどを直接使わず、int16型やuint16型といった型定義を⽤いる事でソースコードの移植性を⾼める

例）
typedef signed char
int8_t;typedef unsigned char uint8_t;
typedef signed short
int16_t;
typedef unsigned short uint16_t;© 2016 Sunny Giken Inc. All rights reserved.

-6-

ISO/IEC
9899:1999(以降C99)では、サイズが保障される左記の型が⽤意されている

コード事例１ （補⾜）<第3版(MISRA C:2012)の変更点>

Directive 4.6(推奨)
基本的な数値型の代わりに、サイズと符合属性を⽰す
typedefを⽤いるべきである。

MISRA-C:2004まではRuleとして括られていたものが、MISRA C:2012では適合/⾮適合がソースコードのみで判断できないものをDirective に、判断できるものを Ruleに分類するようになりました。

© 2016 Sunny Giken Inc. All rights reserved.

-7-コード事例２（問題）aの値を2進数で表すと？

int8_t a;a = -18;①10010010 ②11101101 ③11101110© 2016 Sunny Giken Inc. All rights reserved.

-8-コード事例２（回答）

int8_t(符号付き1バイト)の場合
7

6

5

4

3

2

1

0

左端が、符号ビット(0:正の数、1:負の数)18から-18を作る⼿順①18を2進数に直す②ビットを反転③1を加える

00010010
11101101
111011102の補数と呼びます© 2016 Sunny Giken Inc. All rights reserved.

-9-コード事例２（補⾜）aの値を2進数で表すと？

int8_t a;a = -18;①10010010 ②11101101 ③11101110

絶対値法
符号＋仮数部

1の補数

2の補数

C⾔語の負数の内部 表現は処理系定義であるため、必ずしも２の補数ではない。
© 2016 Sunny Giken Inc. All rights reserved.

- 10 -

コード事例３（問題）dの値は？

a = 0x55;
b = 0x0f;
c = 1;
d = a & b + c;
①0x06、②0x10、③その他© 2016 Sunny Giken Inc. All rights reserved.

- 11 -

コード事例３（回答）a = 0x55;
b = 0x0f;
c = 1;
d = a & b + c;
&演算⼦と+演算⼦では、+演aとb+cの評価の値を& 算⼦の⽅が優先順位が⾼いため
b+cが先に処理され、評価の値演算し、0x10となる
は、0x10

よって、dは0x10© 2016 Sunny Giken Inc. All rights reserved.

- 12 -

コード事例３（解説）< MISRA C:2012で検出 >Rule 1２.１
式中における演算⼦の優先順位は、明⽰的にすべきである。

演算⼦の優先順位を明確にすることにより，設計者の意図が誤解されるリスクを軽減します。

例）
d = a & (b + c);© 2016 Sunny Giken Inc. All rights reserved.

- 13 -

コード事例３（補⾜）説明

演算⼦あるいはオペランド

優先順位

プライマリ

識別⼦，定数 ⽂字列リテラル，(式)

16（⾼）

後置

[]，() (関数呼出し)，.，->，++ (後置インクリメント)，-- (後置デクリメント)，()｛｝ （C99：複合リテラル）

15

単項++ (前置インクリメント)，-- (前置デクリメント)，&，*，+，-，~，!，sizeof，defined (前処理系)

14キャスト

()

13乗除

*，/，%

12加減

+，-

11

ビット単位のシフト

<<，>>

10

関係<，>，<=，>=

9

等価==，!=

8ビット単位のAND&

7

ビット単位の排他OR^

6

ビット単位のOR

|

5

論理AND

&&

4

論理OR

||

3

条件?:

2

代⼊

=，*=，/=，%=，+=，-=，<<=，>>=，&=，^=，|=

1

カンマ,0（低）© 2016 Sunny Giken Inc. All rights reserved.

- 14 -

コード事例４（問題）a、ｂ、cのそれぞれの値は？

a = 0;
b = 0;
c = a +++ b;①aは0、bは1、cは1②aは1、bは0、cは0③aは1、bは0、cは1④その他© 2016 Sunny Giken Inc. All rights reserved.

- 15 -

コード事例４（回答）a = 0;
b = 0;
c = a +++ b;
演算⼦の優先順位より、(a++) + bとなる
a++は、後置インクリメントのため、c = a + bの計算には、インクリメント前のaの値が使われる

よって、aは1、bは0、ｃは0© 2016 Sunny Giken Inc. All rights reserved.

- 16 -コード事例４（解説）< MISRA C:2012で検出 >Rule 13.3
インクリメント(++)またはデクリメント(--)演算⼦を含む完全式には、インクリメント演算⼦またはデクリメント演算⼦に起因する副作⽤以外の潜在的副作⽤があってはならない。
インクリメントまたはデクリメント演算⼦を含む式は、オブジェクトの変更という副作⽤を⽣じる。そのため、他の副作⽤と混在させると式が分かりにくくなる
ため、インクリメントまたはデクリメント演算⼦を他の演算⼦と切り離して使⽤すると、式が分かりやすくなります。

例）
c = a + b;a++;
© 2016 Sunny Giken Inc. All rights reserved.

- 17 -

コード事例４（補⾜）完全式
他の式の⼀部でもなく宣⾔⼦の⼀部でもない式

副作⽤

実⾏環境に変化を⽣じる次の内容を副作⽤という。
u volatile オブジェクトへのアクセス
u オブジェクトの変更
u ファイルの変更
u これらいずれかの操作を⾏う関数の呼出し© 2016 Sunny Giken Inc. All rights reserved.

- 18 -

コード事例５（問題）yの値は？

x = 0;
y = x/++x;①0 ②1 ③その他
© 2016 Sunny Giken Inc. All rights reserved.

- 19 -

コード事例５（回答）x = 0;
y = x/++x;
分⼦を先に評価すれば、０/１で「yは０」となる

分⺟を先に評価すれば、１/１で「yは１」となる

yの値は、不定２つのオペランドの評価順序はＣ⾔語規格で© 2016 Sunny Giken Inc. All rights reserved.

- 20 -

コード事例５（解説）< MISRA C:2012で検出 >Rule 13.2
式の値と持続的な副作⽤は、すべての許可された評価順序の元で同じでなければならない。
Rule 13.3
インクリメント(++)またはデクリメント(--)演算⼦を含む完全式には、インクリメント演算⼦またはデクリメント演算⼦に起因する副作⽤以外の潜在的副作⽤があってはならない。

© 2016 Sunny Giken Inc. All rights reserved.

- 21 -

コード事例６（問題）xの値は？

x = 1;if(x = 0){x = 2;}①0 ②1 ③2 ④その他
© 2016 Sunny Giken Inc. All rights reserved.

- 22 -

コード事例６（回答）x = 1;
if(x = 0){x = 2;}
よって、x は０© 2016 Sunny Giken Inc. All rights reserved.

- 23 -

xに0が代⼊“==”とされ、偽と”=“の誤りかも?
なるコード事例６（解説）< MISRA C:2012で検出 >Rule 13.4
代⼊演算⼦の結果は、⽤いるべきではない。

Rule 13.4が、⾮適合となるその他の例例）
x = 0;a[ x ] = a[ x = 1 ];© 2016 Sunny Giken Inc. All rights reserved.

左辺のa[x]のxの値が、０、1のどちらになるかは、未規定のため、「Rule 13.2
式の値と持続的な副作⽤は、すべての許可された評価順序の元で同じでなければならない。」も⾮適合となる。
- 24 -

コード事例７（問題）cの値は？
uint16_t a, b;
uint32_t c;/* 2byte *//* 4byte */a = 0xffff;
b = 0x0002;
c = a + b;
①0x00000001 ②0x00010001 ③その他
© 2016 Sunny Giken Inc. All rights reserved.

- 25 -

コード事例７（回答）uint16_t
uint32_ta, b;c;/* 2byte *//* 4byte */a = 0xffff;
b = 0x0002;
c = a + b;
intｻｲｽﾞが16bitなら”Yes”どういう型（サイズ）で演算されるか？
intｻｲｽﾞが32bitなら”No”
両⽅ともにuint16_tなのでuint16_tで加算

左辺がuint32_tなのでuint32_tで代⼊値を⼊れてみると0x00000001

0xffff + 0x0002 → 0x0001

Cは、0x00000001 というのは誤り© 2016 Sunny Giken Inc. All rights reserved.

- 26 -

コード事例７（回答）

intサイズが、32bit(32bitマイコン)の場合

c = a + b;
どういう型（サイズ）で演算されるか？
左辺がuint32_tなのでuint32_tで代⼊両⽅ともにuint16_tであるがint32_tで加算（汎整数拡張によりintｻｲｽﾞになる）

値を⼊れてみると0x00010001

0x0000ffff + 0x00000002→ 0x00010001

intサイズが16bit時は、0x00000001
intサイズが32bit時は、0x00010001© 2016 Sunny Giken Inc. All rights reserved.

- 27 -

コード事例７（解説）< MISRA C:2012で検出 >Rule 10.6
より⼤きな本質型を持つオブジェクトに複合式の値を代⼊してはならない。
リスクを回避するなら例）ラップアラウンド
させたい場合c = (uint16_t)(a + b);© 2016 Sunny Giken Inc. All rights reserved.

- 28 -例）ラップアラウンド
させたくない場合
c = (uint32_t)a + b;

コード事例８（問題）

バイトオーダーがリトルエンディアンの場合、どのアドレスにどの値が書き込まれるか？

uint8_t *p;
p = (uint8_t *)0x401;*(uint16_t *)p = 0x1234;
Address

Value

400h?

401h?

402h?

403h?

© 2016 Sunny Giken Inc. All rights reserved.

①401h番地が0x12、402h番地が0x34②401h番地が0x34、402h番地が0x12③その他- 29 -

コード事例８（回答）uint8_t *p;
p = (uint8_t *)0x401;*(uint16_t *)p = 0x1234;
Address

Value

400h?

401h

0x34

402h

0x12

403h?

リトルエンディアンの場合401h番地に0x34、402h番地に0x12となる© 2016 Sunny Giken Inc. All rights reserved.

- 30 -コード事例８（補⾜）エンディアン
エンディアンとは、多バイトデータをメモリ上に配置する⽅式のことであり、C標準規格では処理系定義となります。
エンディアンには主にリトルエンディアンとビッグエンディアンの2種類があり、それぞれデータをメモリに配置する⽅向に違いがあります。

*(uint16_t *)p = 0x1234;
リトルエンディアンの場合

ビッグエンディアンの場合

Address

Value

Address

Value

400h?

400h?

401h0x34

401h

0x12

402h

0x12

402h

0x34403h?

403h?

© 2016 Sunny Giken Inc. All rights reserved.

- 31 -コード事例８（回答）uint8_t *p;
p = (uint8_t *)0x401;*(uint16_t *)p = 0x1234;
AddressValue

400400h?
0x34

401401h

340x12402402h12?

403403h?

マイコンによっては、奇数アドレスに配置された1バイト境界線のポインタを、2バイト境界線のポインタにキャストした
場合、意図通りにアクセスできない可能性がある

よって、マイコンによっては、意図した場所に配置されない場合がある© 2016 Sunny Giken Inc. All rights reserved.

- 32 -コード事例８（補⾜）アライメントアライメントとは、データ境界とも呼ばれるメモリへのデータア
クセスの単位であり、C標準規格では処理系定義となる。⼀般的には２nバイトの汎⽤レジスタやデータバスのサイズと同じサイズとなります。またこれをアクセスするサイズに合わせ、「バイト境界」、「ワード（２バイト）境界」などと呼びます。
①2バイトに合わせたアドレスに配置された変数へのアクセス
Address Value
400h

0x34

401h

0x12

アクセスは1度
0x1234②2バイトにあっていないアドレスに配置された変数へのアクセス
アクセスは1度
各シフト後に論理和
Address Value
400h

0x56401h0x34

402h

0xF0

402h

0x12

403h

0xDE

403h

0xF00x3456 0x0034
右シフト+0xF012 0x1200
論理和

左シフト0x1234© 2016 Sunny Giken Inc. All rights reserved.

- 33 -

コード事例８（解説）< MISRA C:2012で検出 >Rule 11.3
オブジェクト型へのポインタと異なるオブジェクト型へのポインタとの間でキャストを⾏ってはならない。
リスクを回避するなら例）*p = 0x34;*(p+1) = 0x12;© 2016 Sunny Giken Inc. All rights reserved.

- 34 -

コード事例９（問題）

このコードのリスクは何でしょうか？

a = b = 0;
© 2016 Sunny Giken Inc. All rights reserved.

- 35 -コード事例９（回答）uint8_t a, b;
a = b = 0;
a = 0;
b = 0;
a、ｂそれぞれに0を代⼊する処理となり、リスクなし© 2016 Sunny Giken Inc. All rights reserved.

- 36 -

コード事例９（回答）volatile uint8_t a, b;
a = b = 0;
左記の順で処理された場合、aが0となるとは限らない

b = 0;
a = b;© 2016 Sunny Giken Inc. All rights reserved.

- 37 -

コード事例９（解説）JIS(C90) 6.3.16 より代⼊演算⼦は、左オペランドで指し⽰されるオブジェクトに値を格納する。代⼊式は、代⼊後の左オペランドの値をもつが、左辺値ではない。代⼊式の型は、左オペランドの型とする。ただし、左オペランドの型が修飾型である場合を除く。この場合、その型は、左オペランドの型の⾮修飾版とする。左オペランドに格納されている値を更新する副作
⽤は、前の副作⽤完了点から次の副作⽤完了点までの間に起こらなければならない。

⾚字の箇所の規定で連続代⼊中はvolatileではなくなります。

© 2016 Sunny Giken Inc. All rights reserved.

- 38 -

コード事例９（解説）volatile uint8_t a, b;
a = b = 0;
b = 0;
a = 0;

代⼊処理の順序は？

ora = 0;b = 0;

リスクは？
l Volatileの場合、代⼊の順序が影響を与える可能性がある。
l 実装者は、b = 0、a = bを期待していた可能性がある。
© 2016 Sunny Giken Inc. All rights reserved.

- 39 -

コード事例９（解説）< MISRA C:2012で検出 >Rule 13.4
代⼊演算⼦の結果は、⽤いるべきではない。
リスクを回避するなら例）
b = 0;
a ＝ 0;© 2016 Sunny Giken Inc. All rights reserved.

- 40 -

まとめ
C言語は、多くのプロセッサで利用可能、効率的な機械コードにコンパイルできる、シンプル等、多くの利点がある一方、これまで出題してきた問題にもあった通りC言語には、いくつかの弱点があります。
u ⾔語の未定義、未規定の領域がある
u 他の⾔語より多くの演算⼦があり、それらの優先順位や型ルールが分かりづらい
u 良くありがちな問題(演算例外、オーバーフロー等)の実⾏時チェックをコンパイラが提供していない。
MISRA Cは、C⾔語のサブセットであり、上記のようなC⾔語の弱点よる問題を除去または削減するためのガイドラインです。
MISRA Cは、ルールを守るだけのものではなく、MISRA Cを理解することにより、C⾔語を理解するための教材としても有効です。

© 2016 Sunny Giken Inc. All rights reserved.

- 41 -

最後に組込み開発者におくる
MISRA C:2012
C⾔語利⽤の⾼信頼化ガイド
2016年10⽉電⼦書籍(kindle)にてリリース予定

Coming soon!
© 2016 Sunny Giken Inc. All rights reserved.

- 42 -