サンプル::#defineをやめる

サンプル::#defineをやめる

#defineをやめる 09:25

C言語の最悪の機能を一つ挙げろといわれれば、私は#defineを挙げます。#defineマクロは確かに重宝しますが、システム定義ファイルとしてマクロを1000個も定義したものを渡されると、うんざりしてしまいます。#defineマクロは大域的なので二つのインクルードファイルに同じ名前のマクロがあったりすると気が滅入る問題を起こします。

幸いC++にはconst変数があります。これはコンパイラに定数として解釈される変数で、多くの場合マクロ定数の代わりとして利用できます。前回使ったLED点灯プログラムのマクロをこれを使って定義しなおしましょう。

マクロをconst変数に置き換えると次のようになります。

volatile unsigned char * const pFLASHA_PORTB_OUT=(volatile unsigned char *)0x20270005;
volatile unsigned char * const pFLASHA_PORTB_DIR=(volatile unsigned char *)0x20270007;

長い長い行になってしまいますが、私はPascalが長かったので少し余計に書いてプログラムの安全性をコンパイラ任せにできるなら気になりません。右辺にマクロ定義で使っていた型キャストつきアドレスです。左辺がポインタ変数定義でこのポインタはconst宣言されているのでポインタの値(アドレス)は定数として使われます。ポインタが指し示す変数の値はvolatile宣言されています。

これで自分が定義するマクロ定数は一掃できますが、cdefBF53x.hによって提供される数百のマクロ定数は未解決です。ところが、これには逃げ道があります。

アナログデバイセズの日本語技術資料ページにあるEEJ-017とそのサンプルプログラムはこの問題に対する解決策を提供しています。EEJ-017のサンプルとして供給されるcppdefBF53x.hはcdefBF53x.hのマクロをすべてconst変数に書き換えた上で、名前空間に閉じ込めています。また、供給されるポインタの型は同じです。したがって、cdefBF53x.hの代わりにcppdefBF53x.hをインクルードして名前空間mmrの中のポインタを使えば問題は一挙解決です。

// EZ-KIT LED点灯プログラム
#include<cppdefBF53x.h>
  // FLASH AのポートB設定レジスタ
volatile unsigned char * const pFLASHA_PORTB_OUT=(volatile unsigned char *)0x20270005;
volatile unsigned char * const pFLASHA_PORTB_DIR=(volatile unsigned char *)0x20270007;

int main(void)
{
  *mmr::pEBIU_AMBCTL0 = 0x7bb07bb0;  // 非同期ポート0,1の初期化
  *mmr::pEBIU_AMBCTL1 = 0x7bb07bb0;  // 非同期ポート2,3の初期化
  *mmr::pEBIU_AMGCTL  = 0x000f;      // 全非同期ポートをイネーブル

  *pFLASHA_PORTB_DIR = 0x3f;    // bit0-5を出力に
  *pFLASHA_PORTB_OUT = 0x00;    // LED オフ
  *pFLASHA_PORTB_OUT = 0x31;    // 110001を出力
}

mainの中を見るとpEBIU_xxxxポインタが名前空間mmrの中にあるので可視性解決のためにmmr::が追加されています。それ以外は前回のプログラムと変りません。

記述が冗長になりますが、大規模プログラムを考えている場合にはいいかもしれません。