Version 6.06
プリプロセッサ色々
「前回は #define の使い方を中心にマクロとかの解説をしてきました」
『よーするにプリプロセッサは使うな! ってことよね』
「僕的にはね。でも、実際にはもういろんな所で使われてるから。今回はそ
ういう使用例を見つつ、色々なプリプロセッサについて解説します」
『ほい』
「まず、 #define の有効範囲について。たとえばこんな例」
void HasDefine()
{
#define DEF_FLAG_OK 1
}
void UseDefine()
{
TRACE( "%d\n", DEF_FLAG_OK );
}
『両方関数だね。上の関数の中で #define で定数作ってて、下の関数の中
でその DEF_FLAG_OK を使ってる……って、それってできるの?』
「できるんです。もし #define じゃなく const int を使ってたらこれはで
きないんだけど、 #define は」
『ただの置き換え! つまり #define は変数じゃないからそーゆーの関係
ないんだ』
「そういうこと。これが問題になる場合があるんだよね」
『どういうとき?』
「たとえば API の Windef.h に max っていうマクロがあります」
#define max(a,b) (((a) > (b)) ? (a) : (b))
『右っかわよくわかんない……』
「これは今回はパス。で、 max っていうのはすごくよくある単語だから、
このマクロの存在がまずいことになることがあるんです」
『っつーことは、普通にプログラムで max って単語は使えないんだ』
「そういうこと。しかも、 #define は関数とかネームスペースとか全然関
係ないから」
『上のみたいに、他の関数に土足で踏み込んじゃうとかあるんだねー』
「そこで、この #define を解除するプリプロセッサを紹介します。それは
#undef 」
void HasDefine()
{
#define DEF_FLAG_OK 1
#undef DEF_FLAG_OK // 解除!
}
void UseDefine()
{
TRACE( "%d\n", DEF_FLAG_OK );
// error C2065: 'DEF_FLAG_OK' : 定義されていない識別子です。
}
『おお、 DEF_FLAG_OK が見つかってない!』
「この #undef を使うと、 #define したものを無効にすることができるん
です」
『これでさっきの max とか無効にできるんだね』
「さて、この #undef 以上に使われるのが、 #if 系のプリプロセッサ」
『 #if 系、ってことはいっぱいあるんだ。普通の if と違うの?』
「ううん、基本的には同じ。ゼロ以外か、ゼロか、で分岐されるものはね。
とりあえず例を見て」
#if 1
TRACE( "IF_FLAG : Non 0 \n" );
#endif
「 #if は、すぐ右側がゼロ以外ならすぐ下から #endif までを残して、ゼ
ロだとその部分を削除します」
『?』
「このままの例だと、 #if の右がゼロ以外だから、上の3行は」
TRACE( "IF_FLAG : Non 0 \n" );
「ってなります」
『 #if と #endif の間の行が残るって事ね』
「もし #if 0 って書いてあったら、上の3行は」
「つまり空白になります」
『つまり、プログラムができたりできなかったり、ってなるんだ。 #endif
は } 代わりね』
「そう。 { はないけどね」
『ないけど、インデントするのは見やすいから?』
「一応ね。しない人もいるし、場合によって異なるから、これは難しいか
も。次回紹介する例でも紹介するから」
『ふーん。質問! 1 とか 0 とか書いてるけど、直接書いてたら #if の意
味ないじゃん。コンパイルの前だから、変数とかとも関係ないし』
「同じ、コンパイルの前に数字作れるのあるでしょ」
『ってことは、 #define ?』
「そゆこと。 stdafx.h にこういうのがあるでしょ」
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
「この _MSC_VER を MSDN で見てみて」
『ほいF1。【組み込みマクロ】って出た』
「組み込みマクロは、初めっから #define されてる値のこと。こういう値
を使えば」
『 #if で分岐できるわけだ』
「 #pragma once は次回に取っといて、次に #else について」
#if 1
TRACE( "IF_FLAG : Non 0 \n" );
#else
TRACE( "IF_FLAG : 0 \n" );
#endif
『普通に else と同じって考えれば、 #if がゼロ以外なら』
TRACE( "IF_FLAG : Non 0 \n" );
『で、ゼロなら』
TRACE( "IF_FLAG : 0 \n" );
「そういうこと。もうひとつ #elif について紹介します。これは else if
にあたるもの」
#define DEF_FLAG 15
#if DEF_FLAG < 10
TRACE( "DEF_FLAG : - 10 \n" );
#elif DEF_FLAG < 20
TRACE( "DEF_FLAG : 10 - 20 \n" );
#else
TRACE( "DEF_FLAG : 20 - \n" );
#endif
『 #elif って妙な感じ。ま、 if 系とほとんど同じだから分かりやすいけ
どね』
「そうだね、ほとんど変わらないと思うよ」
『あ、あと #if - #endif の中に #if - #endif を入れる事ってできる?』
「もちろんできるよ。 #if と #endif の間には特に制限はないから」
『ほうほう、だいたい普通の if と同じね』
「さて、ここからちょっと重要。実際には、 #if は使わないか、他と組み
合わせて使うことが多かったりします。その組み合わせる時に使うのは、
defined というもの」
#define DEF_FLAG
#if defined DEF_FLAG
TRACE( "DEF_FLAG : Defined \n" );
#else
TRACE( "DEF_FLAG : Not Defined \n" );
#endif
『 #if のすぐ右にあるね』
「この #if defined は、すぐ右の単語が #define されていればゼロ以外
、されてなかったらゼロと同じように振る舞います」
『ってことは、最初の #define DEF_FLAG をコメントアウトしたら、下の
方だけってことになるんだ』
「そゆこと。ちなみに DEF_FLAG が何に #define されてようが関係ないか
ら」
『そりゃそーね、この例だと空白になってるんだもん』
「あと〈定義されてない場合〉を使うことも多かったりします」
#if !defined DEF_FLAG
TRACE( "DEF_FLAG : Not Defined \n" );
#else
TRACE( "DEF_FLAG : Defined \n" );
#endif
『 ! は逆になるんだよね』
「そう、 if の時に使った ! と同じ意味で、この例だと〈 DEF_FLAG が
#define されていなかったら〉って条件になります」
『ちょっとややこしいかな』
「さらに、 #if defined と #if !defined はよく使われるんで、それぞれ
#ifdef と #ifndef っていうプリプロセッサが用意されてます」
『おお!』
「使い方はほとんど同じ。まず #ifdef 」
#define DEF_FLAG
#ifdef DEF_FLAG
TRACE( "DEF_FLAG : Defined \n" );
#else
TRACE( "DEF_FLAG : Not Defined \n" );
#endif
『これはさっきの #if defined と同じね』
「もひとつ #ifndef 」
#define DEF_FLAG
#ifndef DEF_FLAG
TRACE( "DEF_FLAG : Not Defined \n" );
#else
TRACE( "DEF_FLAG : Defined \n" );
#endif
『これは #if !defined と同じね』
「で、 #if defined 系と #ifdef 系、どっちを使うかだけど、基本的には
どっちでもいいです」
『そりゃそうよね、機能同じなんだし』
「ただ僕的には #if defined 派かな」
『お、出た水希ちゃん流。その理由は?』
「 #ifdef と #ifndef は n ひとつしか違わないから分かりにくくて。
#if defined と #if !defined の違う点、 ! の有無は色違いで気付きやす
いから」
『記号だもんね』
「だから僕は #if defined を勧めます」
/*
Preview Next Story!
*/
『こんなんでプログラムが変わるんだね〜』
「ちょっと楽しい?」
『少し、ね』
「じゃ、来週はその楽しい気持ちをそぎ落としましょう」
『げげ』
「というわけで次回」
< Version 6.07 条件コンパイルの世界 >
『につづく!』
「火美ちゃんもプリプロセッサ嫌いになれ〜」
『イヤ〜!』