| リスト6−1 ダミー関数 |
1 win_bell()
2 {
3 fprintf( stderr, "win_bell() is not supported\n" );
4 }
5
6 Notify_value notify_next_event_func()
7 {
8 fprintf( stderr, "notify_next_event_func() is not supported\n" );
9 }
10
11 pw_batch()
12 {
13 fprintf( stderr, "pw_batch() is not supported\n" );
14 }
15
16 Event *canvas_window_event()
17 {
18 fprintf( stderr, "canvas_window_event() is not supported\n" );
19 }
|
ダミー関数は、とりあえず関数がないとリンクできず、デバッグを進められないときなどに必ず 必要になります。プログラムが大きくなると、全ての関数を用意してからテストということはなく、 開発の初期には、ダミー関数の山でしょう。だから、用意するダミー関数の数が何十個にもなるこ とは珍しくありません。そのようなとき、リスト1のように、関数名以外は全く同じ関数を繰り返 して書くことは退屈な、ばかばかしい作業です。
当然、マクロの出番です。マクロは、短い文字列の置換だけでなく、行末を\(¥)で継続する ことで、何行にもわたる長いマクロが定義できます。
ここでは、マクロの引数にダミー関数名を与えることで、
MakeDummyFunction(win_bell)
と書くだけでダミー関数が1つ作れるようにします。マクロの置換は、単なる文字列の置換で、C
言語の文法に従って置換する訳ではありませんから、文字列中にも仮引数と一致する文字列がある
と置換されます。これで、多数のダミー関数があっても、リスト6−2のようにすればあっという
間に作れるでしょう。
「せこい」と言われようが、こういう技巧も心得ていないと開発に余分な時間がかかります。
| リスト6−2 マクロで大量生産したダミー関数 | |
1 #define MakeDummyFunction( type, fn ) \
2 type fn() \
3 { \
4 fprintf( stderr, #fn "() is not supported\n" ); \
5 }
6
7 MakeDummyFunction( int, win_bell )
8 MakeDummyFunction( Notify_value, notify_next_event_func )
9 MakeDummyFunction( int, pw_batch )
10 MakeDummyFunction( Event *, canvas_window_event )
|
| リスト6−3 # 行のあるソース |
1 caddr_t menu_get( menu_obj, op )
2 IN myMenu_object *menu_obj;
3 IN Menu_attribute op;
4 {
5 va_list ap;
6 caddr_t value = NULL;
7
8 #ifdef DEBUG
9 printf( " >>> enter menu_get\n" );
10 #endif
11
12 if( ! menu_obj ) {
13 printf( " menu_get() .. menu_object is NULL\n" );
14 goto ending;
15 }
16
17 switch( TYPE_OF_MENU_OBJECT( menu_obj ) ) {
18 case MENU_OBJECT_MENU:
19 value = smenu_get_menu( (myMenu*)menu_obj, op );
20 break;
21 case MENU_OBJECT_MENU_ITEM:
22 value = smenu_get_item( (myMenu_item*)menu_obj, op );
23 break;
24 }
25 ending:
26
27 #ifdef DEBUG
28 printf( " <<< exit menu_get\n" );
29 #endif
30 return value;
31 }
|
また、#ifdefと#endifで囲むのが面倒だし、どうせすぐに消すからと、printfまたはfprintfな どで直接書いてしまうことも多いでしょう。
こういうとき、ヘッダーファイル中に、
#ifdef DEBUG
#define DebugPrint( message ) fprintf( stderr, message )
#define DebugPrint2( f, a, b ) fprintf( stderr, f, a, b )
#else
#define DebugPrint( message )
#define DebugPrint2( f, a, b )
#endif
と書いておけば、#ifdef,#endifがなくなり、はるかに読みやすくなります。単純なメッセージは
DebugPrintを、データを伴うものはDebugPrint2を使ってみてください。
#ifdefと#endifがいっぱい出てくると、読みづらくてたまりません。これは、C言語特有の字下 げの効果を破滅させるからです。長いプログラム中に、#ifdefと#endifが頻繁に出てくるのは、た とえデバッグ中でもいやなものです。上の方法では、デバッグライトが字下げを妨害しません。こ の効果はリスト6−4に出ています。プログラムが長くなると、もっともっと差が歴然としますが、 それは想像してください。
| リスト6−4 # 行を取り除いたソース |
1 caddr_t menu_get( menu_obj, op )
2 IN myMenu_object *menu_obj;
3 IN Menu_attribute op;
4 {
5 va_list ap;
6 caddr_t value = NULL;
7
8 DebugPrintf( " >>> enter menu_get\n" );
9
10 if( ! menu_obj ) {
11 DebugPrint( " menu_get() .. menu_object is NULL\n" );
12 goto ending;
13 }
14
15 switch( TYPE_OF_MENU_OBJECT( menu_obj ) ) {
16 case MENU_OBJECT_MENU:
17 value = smenu_get_menu( (myMenu*)menu_obj, op );
18 break;
19 case MENU_OBJECT_MENU_ITEM:
20 value = smenu_get_item( (myMenu_item*)menu_obj, op );
21 break;
22 }
23
24 ending:
25 DebugPrint( " <<< exit menu_get\n" );
26 return value;
27 }
|
#define IN
#define OUT
#define INOUT
と定義しているため、プリプロセッサでマクロ展開されると無くなってしまい、何も書かなかった
のと同じ、つまりコメントと同様になります。コメントは、/* と */ に囲まれているので、邪魔
くさい感じがします。C言語の予約語にみえるようにするためには、in, out, inout と小文字に
することもできます。
何かに変換するだけがマクロの使い道ではありません。「無」への置換はいろいろ応用範囲が広 いので覚えておいてください。