#pragma twice

KAB-studio > プログラミング > #pragma twice > 105 Version 6.05 プリプロセッサとマクロ

#pragma twice 105 Version 6.05 プリプロセッサとマクロ

前のページへ 表紙・目次へ 次のページへ

 Version 6.05
プリプロセッサとマクロ

ここ最近よく出てくる #include や #define 
最初が # で始まる謎なヤツ
こういうのを〈プリプロセッサディレクティブ〉って言います
??
英語で書くと Preprocessor Directive 。 Pre-process は〈事前処理〉
って意味。 Directive は指示する物って意味
前は〈プリプロセッサ〉って、〈ディレクティブ〉は省略してなかったん
じゃない?
うん、長いからプリプロセッサ、さらに〈マクロ〉って言うことも多いか

なんか全然違うけど……
マクロの話は後半で。ここでは〈プリプロセッサ〉で統一します
で、〈事前処理〉って何の前処理?
コンパイルの。つまりプリプロセッサディレクティブは、コンパイル前に
色々と処理をするためのものってこと
コンパイル前、ねぇ
分かりにくいかもね。ひとつ例を挙げると

const int DEF_FLAG_OK = 1;

定数作るのだね
これと

#define DEF_FLAG_OK 1   // 定数。

あ、これも定数作るのだ。でもこれはプリプロセッサのだね
機能的にはこのふたつは似てるけど、仕組みがまったく違うんです。まず
const int の方。これは普通の int 型の、中身を書き換えられない変数
中身を書き換えられない変数、って変くない?
変くない?よりは変じゃない
うー
で、もうひとつの #define の方。たとえば、この #define ののあとに

    int i = DEF_FLAG_OK;

ってあった場合…… #define の本当の機能、なんだか憶えてる?
単語を置き換える! 前々回に far とかでやったから憶えてるもん
そうでした。そして、 #define はプリプロセッサ、つまりコンパイル前
に処理するんです。ってことは、コンパイルする前に

    int i = 1;

に置き換えられるってこと
ええっ!?
って言っても、実際にファイルの中身が書き換えられるわけじゃないから

あ、そういえばそうね。ってことは……〈書き換えられたとみなされる〉
ってヤツ?
そういうこと! プログラムはプリプロセッサにかけられて整形されて、
それが実際のプログラムとみなしてコンパイルされるんです
ほー。っつーことは、 const の方は普通のプログラムとしてコンパイル
されるんだ
そう、ちゃんとしたプログラムとしてね。ここで重要なのは、プリプロ
セッサが〈コンパイル前に処理する〉ってこと
どゆこと?
火美ちゃんが今言ったように、 const の方はコンパイルしたときにちゃ
んと残ってるから、エラーもそれなりのものになります

    const int DEF_FLAG_OK = 1;
    DEF_FLAG_OK = 100;

 const だからできないよね
だからこういうエラーが出ます

error C2166: 左辺値は const オブジェクトに指定されています。

なんとなくわかるね。で、これを #define に変えると?

#define DEF_FLAG_OK 1   // 定数。
    DEF_FLAG_OK = 100;

あ、エラーが違う

error C2106: '=' : 左のオペランドが、左辺値になっていません。

左のオペランドって、 = の左側ってことだよね、だから DEF_FLAG_OK 
それが #define に置き換わるから?
ってことは……

    1 = 100;

これでエラーになっちゃうんだ
直にこう書いても同じエラーが出るから。で、一番重要な点は、プリプロ
セッサは基本的に分かりにくい! ってこと
分かりにくい?
そう、だって見た目のプログラムが書き変わって、それがコンパイルされ
るんだもの。コンパイルエラーが出ても見つけにくいんだよね
そういえば、前に #define よりも const を使った方がいいって言ってた
けど、それが理由?
それが理由。プリプロセッサはできるかぎり使わない方向に向かってるか
な。でも!
でも?
プリプロセッサは自由度が高いから、昔からかなり色々使われてるんだよ
ね。今も使われてるし。たとえば TRACE() 
え、 TRACE() が!? 関数じゃないの?
関数じゃないんだよね、これが。 #define には、引数を付けることがで
きて、これが関数っぽくできるんです

#define MACRO( x ) TRACE( "%d\n", x ) // マクロ

むー、なんかよくわかんない
つまり

    MACRO( 100 );

ってあったら

    TRACE( "%d\n", 100 );

に置き換わるってこと。普通の #define A B だとスペースが A と B の
区切りだけど、 ( ) の付いたのだと ) が区切りになるから
 ) までのが、そっからあとの ) までと置き換わるってことね
こういう、 #define で作った関数っぽいのが〈マクロ〉って呼ばれるも
のです
これがマクロなのねー。 TRACE() なんかもこういうふうにして作られて
るんだ
基本的にはね。関数と違って、マクロは全部大文字で書くのが一般的
っつーか #define のは全部大文字じゃない?
あ、そうだね。でも const int をそうすることもあるかも。ま、それは
ともかく一番重要なのは、マクロを関数と同じように考えちゃダメ! って
こと
そなの? 普通に使えそうだけど
まず一番大きいのが、置き換えの副作用。まず関数の場合

void NanimoShinai( int p_i )
{
    p_i;
    p_i;
    p_i;
}

これをこう呼び出します

    int i = 100;
    NanimoShinai( ++i );
    TRACE( "%d\n", i );

んーと、っつーか何もしてないんだから、 i が1増えて 101 なだけじゃ

もちろん。で、これをマクロに置き換えてみます

#define NANIMOSHINAIMACRO( x ) \
{       \
    x;  \
    x;  \
    x;  \
}

あ、プリプロセッサは〈改行で終端〉ってみなされちゃうから、そうみな
して欲しくないときには \ を付けます。だからこれは

#define NANIMOSHINAIMACRO( x ) { x; x; x; }

と同じってことだから
 \ は実際には無視して考えればいいんだね
そゆこと。1行の方が〈どう置き換わるか〉は分かりやすいかな
で、これだとどう違う……あっ!  i が 103 になってる!
実際に置き換えてみると分かるけど

    NANIMOSHINAIMACRO( ++i );



    {
        ++i;
        ++i;
        ++i;
    }   

げ! 3回も増えてる!
関数と違ってマクロはそのまんま置き換えるから、こういう問題が出てく
るわけ
関数だと、外と中じゃ全然違う世界だもんねぇ
さらに

#define MAKEERROR( x )  \
{       \
    x;  \
    X;  \
    x;  \
}   

あ、大文字と小文字で間違ってる!
呼び出す部分は

    MAKEERROR( 100 );

ビルドして
ほい。やっぱしエラー出たね
ここで重要なのは、エラーの出る行
行……?  MAKEERROR() 呼び出してる行に出てるね
もし関数なら、 X; \ の行にエラーが出ます
そういえば!
これは大きな問題。これじゃ、 MAKEERROR() のどこが問題なのか分から
ないでしょ
ホントね、 MAKEERROR() の真ん中へんでエラーが出てるはずなのに
というわけで、マクロは一見関数に似てるけど、実はかなり違うものなの
です。というわけで次回に続く!

/*
    Preview Next Story!
*/
もしかして、水希ちゃんてマクロ嫌い?
うん、僕はマクロ反対派
反対派とか賛成派とかあるの?
あるよ。そりゃもう、 ML や掲示板で、血で血を洗う争いが
うわぁ
というわけで次回
< Version 6.06 プリプロセッサ色々 >
につづく!
ま、最近はマクロくらいで論争にはならないだろうけど
じゃあ最近はサンマとかクジラとかで?
魚のマグロ違う〜っ!
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。