「組み込み」ならではの基礎知識 ――スタートアップ・ルーチンからハードウェアまで
4 volatileを指定したくなるとき
volatileということばを聞いたことがありますか?また,volatileの使いかたを知っている人はいますか?volatileは,C言語の解説書ではあまり詳しく説明されていませんが,組み込みソフトウェアでは必須です.
volatileは型修飾子の一つです.型修飾子は型の持つ性質を表すものです.volatileの仲間にはconstがあります.constを思い浮かべれば,型修飾子がどのようなものかを想像できると思います.さて,volatileの説明をKernighan&Ritchieの本『プログラミング言語 C』から引用すると,
「volatileの目的は,黙っていると処理系で行われる最適化を抑止することにある.例えば,メモリ・マップ方式の入出力をもつマシンでは,ステータス・レジスタに対するポインタは,ポインタによる見かけ上,冗長な参照をコンパイラが除去するのを防ぐのに,volatileへのポインタと宣言することが可能である.」
と書かれています.わかりますか?この説明を理解するためには二つのポイントがあります.一つは「黙っていると処理系で行われる最適化」,もう一つは「見かけ上,冗長な」です.これらを説明しながらvolatileを解説します.
●Cコンパイラの最適化を抑止しなければならない理由
まずは,「黙っていると処理系で行われる最適化」について説明します.これはCコンパイラの最適化を指します.Cコンパイラの最適化は,何に焦点を当てるかによっていろいろな最適化があり,そのための手法もいろいろあります.ここでは解説に必要な点しか触れませんが,Cコンパイラの最適化の詳細は今後のしごとにまちがいなく役立つので,ぜひ機会を見て理解しておいてください.
さて,次のプログラムを見てください.
int data; while (1) { if ((data&4) != 0) { 処理1 /* dataに対する代入はないものとする */ } }
このプログラムは,dataのある1ビットの値が1であれば(「ビットが立っていれば」と言う)処理1を実行しろという内容です(プログラム内の&は,ビットごとのANDをとる演算子である).このプログラムのwhile文中ではdataに対する代入がないので,dataの値は変わりません.そのため,while文のループで毎回dataのある1ビットが立っているかどうかを試すのは効率が悪いということがわかります.ですから,ちゃんとしたコンパイラならば,上のプログラムを次のように解釈して,コードを生成します.
int data; if ((data&4) != 0) { while (1) { 処理1 } }
こうすることにより,処理速度が速くなります.これがCコンパイラが行う速度重視の最適化の一例です.