プリプロセッサ 解答ページ | Programming Place Plus C言語編 第23章

トップページC言語編第23章

問題①

問題① 円周率を表す記号定数を定義し、円の面積を求めるプログラムを作成してください。


#include <stdio.h>

#define PI  3.14159265358979323846

int main(void)
{
    puts("円の半径を入力してください。");
    double radius;
    char str[40];
    fgets(str, sizeof(str), stdin);
    sscanf(str, "%lf", &radius);

    printf("この円の面積は %lf です。\n", radius * radius * PI);
}

実行結果:

円の半径を入力してください。
10
この円の面積は 314.159265 です。

円周率の値をどこかで調べてくれば、あとは単に #define で定義するだけです。 このとき、マクロ名は PI などの名前にします。

処理系によっては、<math.h> に M_PI という名前で、円周率の定義が用意されていることがありますが、これは標準のものではありません。

問題②

問題② 次のプログラムを実行すると、出力結果はどうなるか答えてください。

#include <stdio.h>

#define PUT_SW


void func(int num);

int main(void)
{
    func(1);

#undef PUT_SW

    func(2);

#define PUT_SW

    func(3);

#undef PUT_SW

    func(4);
}

void func(int num)
{
#ifdef PUT_SW
    printf("%d\n", num);
#endif
}


出力されるのは、1 と 3 だと思った人は、まだプリプロセスとコンパイルを分離して考えられていません。正解は、次のようになります。

実行結果:

つまり、何も出力されません。

プリプロセッサディレクティブは、コンパイルの前段階で行われます。そこで、まずは # で始まっている行のことだけを考えます。

#define や #undef を繰り返していても、結局のところ一番のポイントは、#ifdef ~ #endif のところです。 この箇所に来たときに、PUT_SW が有効になっているかどうかだけが問題になります。

今はプリプロセスのことだけを考えているので、関数の中にいるとか、処理の流れがどうだとかは「関係ありません」。「#ifdef PUT_SW」の箇所に来た時点では、PUT_SW は最後の #undef によって無効になっているので、条件式は偽になります。

したがって、このプログラムはコンパイル段階には、次のような状態になっています。

(※stdio.h の内容がある)



void func(int num);

int main(void)
{
    func(1);


    func(2);


    func(3);


    func(4);
}

void func(int num)
{
}

結局、func関数の中身は空になってしまうので、どの位置から func関数を呼び出そうと関係なく、つねに何も出力されません。

問題③

問題③ まず、次のプログラムを見てください。

#include <stdio.h>

int main(void)
{
    puts("1");
    puts("2");
    puts("3");
    puts("4");
}

#if を使って、3 を出力している puts関数の呼び出しをコメントアウトしてください。さらに、その後、すべての puts関数の呼び出しをコメントアウトしてください。

/* と */ によるコメントアウトと比較すると、どのような違いがありますか?


まず、puts("3"); をコメントアウトします。

#include <stdio.h>

int main(void)
{
    puts("1");
    puts("2");
#if 0
    puts("3");
#endif
    puts("4");
}

次に、すべての puts関数の呼び出しをまとめてコメントアウトします。

#include <stdio.h>

int main(void)
{
#if 0
    puts("1");
    puts("2");
#if 0
    puts("3");
#endif
    puts("4");
#endif
}

実行結果:

このように、#if 0 と #endif で囲む方法であれば、入れ子のかたちにでもコメントアウトできます。 /* と */ で囲む方法だとうまくいきません。

#include <stdio.h>

int main(void)
{
/*
    puts("1");
    puts("2");
/*
    puts("3");
*/
    puts("4");
*/
}

最後の */ よりも前で、コメントは効果は終わってしまい、最後の */ は単なる余計な文字として残ってしまいます。この余計な文字のせいで、コンパイルエラーになってしまいます。



参考リンク


更新履歴

’2018/2/27 全面的に文章を見直し、修正を行った。

’2009/8/13 新規作成。



第23章のメインページへ

C言語編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る