next up previous contents
Next: 26. バイナリーツリー Up: 25. プリプロセッサ Previous: 3. プリプロセッサ cpp

4. 課題 25

cd c を実行した後で( ~/c に移動した後で )、以下の課題を やってみよ。

課題 25.1

マクロ sq(x) について、本文に示した誤った例2つについて実際に cppを用いて、展開結果が間違っていることを確認しなさい。

課題 25.2

プログラムの開発過程ではバグを出す作業をデバッグと呼んでいる。 デバッグの手法にはいろいろなものが考えられているが、最も 原始的でありながら古来より使われている手法に、printf攻撃 と呼ばれるものがある。これは、怪しいとにらんだ主要な変数や 関数の呼び出しなどを、しつこく printf 文を使って表示する ものである。これが本文で紹介した以下のような使い方で、 当然、大量に導入した printf 文をデバッグが終った後に、 わざわざ削除するのも面倒なので、ifdef-endif を 用いて処理している訳である。


    #ifdef DEBUG
        printf("debug: gakusei->point is %d\n",gakusei->point);
    #endif

さて、そうは言ってもいちいち上記のように #ifdef#endif で囲むのも面倒であるので、これをマクロに置き換え ることを考えよう。このマクロを Debug() とし、 プログラム先頭に #define DEBUG があれば、上の ifdef と 同じように働く printf が呼ばれ、なければ何も起こらないような マクロを考えなさい(勿論、この場合引数は2個のみの場合であるが)。


    Debug("gakusei->point is %d\n",gakusei->point);

課題 25.3

ファイルのオープンに際して、


(fp=fopen(file_name,"r"))==NULL
は定型 文であるので、これをマクロにして、read_fopen() というマクロを 作る事を考えよう。このマクロは以下のように使う事を想定している。


    FILE *fp;
    char *file_name="myfile.h";
    ...
    if( read_fopen(fp, file_name ) ){
        /* ファイルのオープンに失敗した場合 */
        printf("Error: cannot open %s\n", file_name);
        exit(1);
    }
    ...

こうなるようなマクロ定義を作成し、展開結果を確かめよ。

同様に、write_fopen()append_open() を 作成せよ。

課題 25.4
課題 22.4 を改良し、標準入力から読み込んでいた部分をファイル "gakusei.data" から読み込むように改造し、更に結果は "gakusei.out" に出力するように改造せよ。なお、ファイルの扱いに際しては 25.3 を 用いよ。

作成したプログラムをメイルで creport まで送りなさい。題は、kadai25 とする事。

前回の復習
プリプロセッサ

コンパイルされる以前にソースに自動的に施される処理をプリプロセス( 前処理)という。#include もプリプロセスの機能の一つであった。

#define 文

    #define  マクロ定義名  [値]
によって、これ以降マクロ定義名で参照したものはプリプロセッサに よって値に置き換えられる。


    #define マクロ定義名(引数並び)  引数を含む文字列

引数を含んだ置き換え機能であるが、副作用などがある点に注意が必要。 引数は括弧で囲んだ上に、引数を含む文字列自体も括弧で囲むのが安全だが、 それでも回避出来ない問題もある。

#ifdef #else #endif文

C の if とほぼ同じ意味であるが、マクロ定義がされていれば真となる。


    #ifdef マクロ定義
    ...
    #else
    ...
    #endif

逆の意味で #ifndef は定義されていなければ真である。

#if #else #endif文

より一般の #if 文も用意されている。

cpp コマンド

プリプロセッサのコマンドは通常 cc から自動的に呼び出されるが、 cpp コマンドを使って明示的に呼び出すことも出来る。



Noriyo Kanayama