「組み込み」ならではの基礎知識 ――スタートアップ・ルーチンからハードウェアまで
先の最適化のところで書いたように,受信処理で0x00efd00c番地への代入がない限り,while文のループで毎回参照するのは効率が悪いのです.つまり「見かけ上,冗長」なのです.しかしこの例では,シリアル・インターフェースのデータ受信が完了した時点で,上のプログラムとは関係のないマイコンのハードウェアがレジスタの値を書き換えてしまうので,毎回参照することに意味があるのです.
このギャップを解消するのがvolatile宣言です.下のようにvolatileを付けることで,Cコンパイラによる最適化は行われず,意図しているように動くことになります.
while (1) { if ((*(volatile unsigned long int *)(0x00efd00c))&4) != 0) { /* 受信完了か */ 受信処理 } }
言い換えると,volatileを付けたデータの値が要求されると,前に同じデータの値が要求されていたとしてもその値を使わずに,その時点のデータの値を必ず読み取るようなコードが生成されます.「直前の同じデータの値を使わずに,その時点のデータの値を読み取る」というのは,「データに書き込まれた値はすぐに消えてしまうので,必要となった時点のデータの値を読み取る」ことだと理解できます.「値はすぐに消えてしまう」ところから,揮発性=volatileというネーミングになったのでしょう.
この例と同様のこと(知らない間に勝手にデータの内容が書き変わるということ)は,割り込み処理やマルチタスクを用いた場合にも発生します.組み込みソフトウェアの場合には,つねに考慮しておくべき状況と言えます.
●格言:シルクハットの中のハンカチは,突然花に変わる
組み込みソフトウェアを作るうえでは,あるデータを「だれが読み書きするか」を考えながらプログラムを作ることが非常にたいせつです.volatileはその第1歩とも言えます.組み込みソフトウェアでは欠くことのできない概念であるvolatileを,この機会にぜひマスタしてください.