2 プリプロセッサー

2.1 プリプロセッサの実行タイミング(p.282)

gcc」を使って,ソースプログラムをマシン語に直すとき,通常はコンパイルす ると言うが,実際にはコンパイル以外の作業も行っている.教科書のp.282に示されてい るように,コンパイルの前にプリプロセッサーがソースファイルを書き直している.そして, コンパイルにより,ソースファイルをオブジェクトファイルに変換している.最後に,リ ンカーがいろいろなファイルを寄せ合わせて実行可能なファイルを作成する.

プリプロセッサーは,コンパイルに先だって,ソースファイルを変更している2gcc ではいろいろな処理が行われるが,プリプロセッサーの動作が一 番最初に実施される.そこで,諸君が書いたC言語のプログラムを変更しているのである. preprocessor(pre:あらかじめ,processor:処理するもの)という名前からも,そのことが よくわかる.

プリプロセッサーができることは,教科書のp.283の表に示されている.いろいろな機能 があるが,本講義で使うのは -4pt

くらいである.

2.2 プリプロセッサの使い方(p.282)

2.2.1 プリプロセッサの書き方

プリプロセッサーの書式は,以下の通りである.今まで,さんざん書いてきているので,大 体理解はできるであろう.
#コマンド パラメーターリスト

このプリプロセッサーの書き方には,以下の約束がある.

2.2.2 ファイルの挿入(p.284)

2.2.2.1 #includeの役割と例

#include "ファイル名"は,指定したテキストファイルとこの行を置き換える.ファ イル名がCfilenameEと鈎括弧CEで書かれた場合には,システムに定義されたファイ ルを示す.unixでは,/usr/include にあるファイルで置き換えられる.プログラマー が作成したファイルを挿入したい場合は, #include "myfile.h" のように記述す る.

プログラマーが自分でヘッダーファイルを書くことがある.例えば,大規模なプ ログラムを作成する場合,ファイルは1つではなく,いろいろな部分を別々のファイルに 書いて,それをあとであわせて,1つのプログラムにする(分割コンパイル).その場合 には,共有する構造体や大域変数を1つのファイルにして,myfile.hというようなファ イルを作り,それぞれのソースプログラムでインクルードする.このようにすると,同じ 文をそれぞれのファイルに記述する必要が無くなり,タイピングが楽になるとともに,ミ スが減る.ここでの学習では,分割コンパイルをするほどのプログラムを書くことはない.将来,比 較的大きなプログラムを書くときに,勉強すればよいだろう.

#includeの動作の理解のために,へんなプログラム例を示す.Hello World !!を出力するおなじみのプログラムである.

   1 #include <stdio.h>
   2 #include "hoge"
   3  return 0;
   4 }

これをコンパイルして,実行ファイルを作るためには,以下のファイル(hoge)が必 要である.当然,このファイルはソースプログラムのインクルード文で取り込まれる.

   1 int main(void){
   2  printf("Hello World !!\n");

実行の結果,#includeにより,そこの行が指定のファイルに置き換わっているのが 理解できるはずである.使い方によっては,便利そうであることが理解できればよい.こ の行の置き換えはコンパイルの前に行われることに注意が必要である.

2.2.2.2 ヘッダーファイル

諸君は,プログラムの最初に必ず#include <stdio.h>とパブロフの犬の如く書いて いただろう.ここにきて,#includeの意味が分かった.stdio.hというファイ ルをインクルードしているだけだ.そうなると,stdio.hを見たくなるのが人情とい うものである.幸い,これはテキストファイルなので見ることができる.以下のコマンド をターミナルへ打ち込んで,stdio.hを見よう.
less /usr/include/stdio.h

キーボーのfで前のページを,bで後ろのページを見ることができる.終わりた い場合は,qを押す.

その中をみると,関数のプロトタイプ宣言等がごちゃごちゃ書かれているのが分かるだろ う.これが,諸君のプログラムの最初の方に追加されるのである.これで, printf()などの関数が使えるようになるのである.

2.2.3 マクロ定義(p.287)

2.2.3.1 文字列置換

#defineはファイル内の文字列を指定の通りに書き換える.単純な文字列の置き換 えと,引数を含む文字列の置き換えがある.引数をとるマクロ定義は,本講義では使う必 要がないので,ここでの学習範囲外とする.

単純な文字列置換をオブジェクト形式マクロと言う.これは,次のように書く

#define hogehoge fugafuga

このプリプロセッサーコマンドがあると,この行以降の文字列hogehogeが文字列 fugafugaに,すべて置き換わる.

置き換え前の文字列--ここではhogehoge--はすべて大文字で記述する習慣 となっている.別に小文字でも問題なく動作するが,ほとんどのプログラマーは大文字を 使う.その方が,プログラムがわかり易いからである.

2.2.3.2 プログラム例

リスト3に,文字列置換を使ったプログラムラム例を示す.4行目の文 字列置換
#define NSTEPS 361

により,全てのNSTEPSという文字列が,361に変えられる.このようにすることによ り,同じ値の部分を一度に変えることができる.プログラムミスが減るので,便利である.

リスト3のプログラムは,三角関数の数表を出力する.0〜2$ \pi$ラジ アンを360等分して,関数の値を計算,そして出力している.例えば,500等分の値を出力 したければ,#define NSTEPS 501とする.文字列置換を使えば,プログラムの変更 が容易であることがわかる.

このプログラムの31行目に,M_PIというわけの分からない変数らしきものがある. 実は,これも文字列置換の対象である.ヘッダーファイルmath.hの中に,

# define M_PI		3.14159265358979323846	/* pi */

と書かれている.ようするに,円周率$ \pi$の値に変換される.ウソだと思うならば,
less /usr/include/math.h

とコンソールに打ち込んで調べよ.

このプログラムは,数学関数--こでは三角関数--を使っている.そのため,ヘッダーファ イルmath.hをインクルードしている.さらに,これをコンパイルするためには,

	gcc -o keisan sankaku.c -lm

lmとオプションを追加する必要がある.


   1 #include <stdio.h>
   2 #include <math.h>
   3 
   4 #define NSTEPS 361
   5 
   6 void cal_function(double x[], double s[], double c[], double t[]);
   7 
   8 /* ==================================================================== */
   9 /*           メイン関数                                                  */
  10 /* ==================================================================== */
  11 int main(void){
  12   double x[NSTEPS], s[NSTEPS], c[NSTEPS], t[NSTEPS];
  13   int i;
  14   
  15   cal_function(x, s, c, t);
  16 
  17   for(i=0; i<NSTEPS; i++){
  18     printf("%f\t%f\t%f\t%f\n",x[i], s[i], c[i], t[i]);
  19   }
  20   
  21   return 0;
  22 }
  23 
  24 /* ==================================================================== */
  25 /*           関数計算                                                    */
  26 /* ==================================================================== */
  27 void cal_function(double x[], double s[], double c[], double t[]){
  28   int i;
  29 
  30   for(i=0; i<NSTEPS; i++){
  31     x[i]=(double)i/NSTEPS*2.0*M_PI;
  32     s[i]=sin(x[i]);
  33     c[i]=cos(x[i]);
  34     t[i]=tan(x[i]);
  35   }
  36 
  37 }


ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
平成19年6月26日


no counter