̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ IT ニュース&コラム 2013/ 9/30 通巻639号 技術版 ソフトウェアデザイン館 Sage Plaisir 21  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ 制御フロー変数を使うな(2) - リーダブル・コード(11) 今回は、「制御フロー変数」が必要になってしまう、条件式の「副作用」と 「短絡評価」について話します。 複数の条件式を AND または OR で分岐する場合、たとえば次のようになります。 if ( p != NULL && memcmp( p, q, 4 ) == 0 ) { ... } && は、短絡評価の演算子(短絡演算子)と呼ばれるもので、&& の左(条件式1) が偽なら && の右(条件式2)を実行しない、|| の左が真なら || の右を実行 しないというものです。 つまり、条件式2以降の結果にかかわらず、条件式1 だけで分岐するかどうか判断できるときは、条件式2を評価(実行)しない というものです。 短絡評価は、Wikipedia によると、ほとんどのプログラミング言語で使え、 JavaScript や Lisp には、短絡評価ではない AND、OR がありません。 なぜなら、条件式2を評価する必要が無ければ評価しないことで、 高速に実行できるようになるからです。 ところで、条件式は評価したかどうかで状況が変わる「副作用」があっては なりません。 たとえば、下記のように printf で表示することは、ユーザー の見た目の状況が変わってしまいます。 おそらくエラーがあったかどうかを 返り値でチェックすることも同時に行っているのでしょう。 if ( printf( "%s\n", s ) == 0 ) { ... } これに対処するには、下記のようにエラーがあったかどうかを判定する値を 変数に代入することです。 これは、制御フロー変数ではありません。 n は、printf の返り値であり、出力した文字数です。 n = printf( "%s\n", s ); if ( n == 0 ) { ... } 条件式に副作用があってはならない理由の1つは、条件判定があっても なくても状況は変わらないことが期待されるからです。 もう1つの理由は、短絡評価にあります。 論理演算子(AND,OR)には、 (短絡しない)標準演算子と短絡演算子の2種類がある(Wikipediaを参照) のですが、それを知らない人が条件式2を実行しない可能性があることに 気づかないことがあるからです。(MISRA-C 2004 12.4) 状況が変わらないことが期待されるからこそ、短絡評価の方が主流に なってきているのです。 静的解析ツールの中には、条件式2に副作用があることを検出して警告 する機能もありますが、正確に検出することは実は不可能です。 なぜなら、関数(例:上記 memcpy か printf)に副作用があるかどうかは、 解析不可能だからです。 つまり、静的解析ツールを通すことが要求された 場合は、条件式に副作用を記述しないのがあたりまえにもかかわらず、 可能性がぬぐいきれないため、便利で主流になっている短絡評価が使えなく なってしまうのです。 まぁ、条件式に副作用を記述してしまうバカな ハッカーがいるのは、JavaScript に見られるいろいろなトリッキーな コードがあることからも事実なのですが。 次のような対策が必要になります。 下記の and, or 変数は、使ってはいけない 制御フロー変数ですが、これを使うしか、静的解析ツールが誤って警告する ことには対処できません。 &&演算子 対策前: if ( p != NULL && memcmp( p, q, 4 ) == 0 ) { ... } 対策後 Type A: if ( p != NULL ) { if ( memcmp( p, q, 4 ) == 0 ) { ... } } 対策後 Type B: bool and; /* Short-circuit evaluation */ and = ( p != NULL ); if ( and ) { and = ( memcmp( p, q, 4 ) == 0 ); } if ( and ) { ... } ||演算子 対策前: if ( p == NULL || memcmp( p, q, 4 ) == 0 ) { ... } 対策後: bool or; /* Short-circuit evaluation */ or = ( p == NULL ); if (!or) { or = ( memcmp( p, q, 4 ) == 0 ); } // or は ! で判定すること if ( or ) { ... } && 演算子と || 演算子の複合 対策前: if ( ( a > 0 && b > 0 ) || ( c > 0 && d > 0 ) ) { ... } 対策後: bool and1, and2; /* Short-circuit evaluation */ and1 = ( a > 0 ); if ( and1 ) { and1 = ( b > 0 ); } and2 = ( c > 0 ); if ( and2 ) { and2 = ( d > 0 ); } if ( and1 || and2 ) { ... } 上記は副作用がないと判定できるため警告されませんが、説明のため分かりやすい 条件式にしています。 参考: リーダブルコード - より良いコードを書くためのシンプルで実践的なテクニック オライリージャパン ISBN-13: 978-4873115658 9.1章 変数を削除する - 制御フロー変数を削除する Wikipedia - 構造化プログラミング 注目ニュース 一覧 ◇ 新型iPhoneはパスワードまる見え!を回避するただ1つの方法。 http://bizmakoto.jp/makoto/articles/1309/25/news016.html … パスワード入力時は表示しないのに。周りに注意してなどの警告確認が必要では。 ◇ チープな iPhone が出なかった理由、あるいはアップルの隠し球。 http://japan.zdnet.com/cio/sp_12mikunitaiyoh/35037455/ http://internet.watch.impress.co.jp/docs/news/20130926_616941.html … 5c はアメリカ向け、4s が中国向け。 ◇ 新型iPhone販売、緒戦はソフトバンク勝利。ドコモ、販路整備遅れ。 http://www.itmedia.co.jp/news/articles/1309/25/news051.html … わずかにソフトバンクが1位だが、3社でほぼ同じ。 ◇ x86版Androidで互換性の問題が非常に少ない理由。 http://pc.watch.impress.co.jp/docs/column/ubiq/20130926_616841.html … x86版は、JavaVMだけじゃない。 ◇ マイクロソフト、Surface Pro 2、Surface 2 を発表。 http://japan.cnet.com/news/service/35037537/ … 高速化、バッテリー時間の増加、薄型化。 ◇ Xbox One開発担当フィル・スペンサー氏インタビュー。 http://av.watch.impress.co.jp/docs/series/rt/20130920_616336.html … Xbox One は、Kinect だけじゃない。 ◇ Mozilla、プラグインを原則ブロックする方針を明らかに。Firefox 26 より実施。 http://www.forest.impress.co.jp/docs/news/20130926_617005.html … プラグインで拡張可能は過去のもの。 ◇ Google Chrome の NPAPI プラグインサポートを段階的に廃止。 http://www.forest.impress.co.jp/docs/news/20130925_616845.html … プラグインで拡張可能は過去のもの。 ◇ 日本人の生真面目さ、画像解析システム普及に逆風か。 http://japan.zdnet.com/cio/sp_13analystview/35037636/ … 完璧じゃないと受け入れないのは、うまく活用できない証拠。 ソフトウェアデザイン館 Sage Plaisir 21 ホームページ >>> http://www.sage-p.com/ メルマガ >>> http://www.mag2.com/m/0000083983.html ブログ >>> http://blog.livedoor.jp/sage_p/ ツイッター >>> http://twitter.com/Ts_Neko ダウンロード >>> http://www.sage-p.com/freesoft.htm サポート掲示板 >>> http://www.sage-p.com/kg_ban09/z6037C8.cgi 東日本大震災 >>> http://www.sage-p.com/saigai.html メール >>> ts-neko◇sage-p.com ←◇を@に変えてください 緊急メールは件名に「うどんメール」を付けてください。 このメルマガの登録・解除 - http://www.mag2.com/m/0000083983.htm