39章 マクロの話

http://www.geocities.jp/ky_webid/c/039.html

マクロの話までやってきました。

マクロとはつまり今まで何度か使ってきた#defineのことです。

関数形式マクロの注意点

ここは必読ですね。

全部読んだところで練習問題です。

問題1

引数で指定された整数の絶対値を返す関数形式マクロを作って下さい。

絶対値ってのは符号い影響されない素の数値ですね。

#define ABS(a) ((a)<0?-(a):(a) )

int main () {
    printf("%d\n",ABS(1));
    printf("%d\n",ABS(-1));
    return 0;
}
1
1

できました。

答え合わせ

あってました。

ライブラリ関数には絶対値を求めるabs関数があります。これはstdlib.hをインクルードして使います。安全性からいえばabs関数の方が安全です。

ということなので基本的にはabs関数を使った方が良さそうです。

問題2

引数で指定された配列に含まれる要素数を返す関数形式マクロを作って下さい。

実はこれ、前に何かで読んでしまったので知ってます。

#define ARRAYNUM(a) (sizeof(a)/sizeof(a[0]))

int main () {
    int num[] = {1,2,3,4};
    
    printf("%d\n",ARRAYNUM(num));
    return 0;
}
4

その配列の持っているサイズを、配列一つのサイズで割れば要素数が割り出せるということですね。

でもちょっと気になったのですが、要素を例えば10にして実際には4つしか使わなかった場合でも10となってしまうんですね。

#define ARRAYNUM(a) (sizeof(a)/sizeof(a[0]))

int main () {
    int num[10] = {1,2,3,4};
    
    printf("%d\n",ARRAYNUM(num));
    return 0;
}
10

これってその配列が何番目まで使用されてるかを知る手段ってないんでしょうか。ちょっと気になりました。

問題3

引数で指定された2つの変数を交換する関数形式マクロは実現可能でしょうか? 可能であれば作って下さい。不可能なら、その理由を答えて下さい。

そもそもマクロで一時変数を用意できるのでしょうか?とりあえず試してみます。

#define INT_SWAP(a,b) {int t=(a); (a)=(b); (b)=t;}

int main () {
    int a=1,b=2;
    
    INT_SWAP(a,b);
    printf("a=%d b=%d",a,b);
    return 0;
}

おお!試行錯誤したらいけました!

とりあえずintのみの交換処理ですができないことはないようです。

答え合わせ

変数workの型の問題と、その宣言が関数の途中に来てしまうことを考えると、SWAPマクロは実現できないことに・・・はなりません。実現は可能です。次のように定義すればいいのです。

#define SWAP(type,a,b) { type work = a; a = b; b = work; }

引数と呼ばれるので気づきにくいですが、関数形式マクロはあくまでも関数ではありません。ただ文字を置換しているだけです。そのため、引数に指定するのは変数や定数である必要はありません。次のように使うことができます。

SWAP(int, num1, num2);

なるほど。マクロって本当にそのまま展開されるだけなんですね、そうであれば確かにこれでいけるってことになります。ちょっと無理やりな気はしますが。