授業/C言語基礎/前処理 のバックアップ(No.2)


Cプログラムをコンパイルすると、まず前処理が行われ、その後、機械語への翻訳が行われます。 前処理を行うための命令をプリプロセッサーと言います。

前処理では、主に、ヘッダー・ファイルの読み込みと、マクロ定義の置き換えが行われます。

ヘッダー・ファイル

#include

printf関数は他のファイルで定義された関数であるのに、externを付けたプロトタイプ宣言なしで使っていました。

実は、printf関数のプロタイプ宣言は、stdio.h というヘッダー・ファイルに、以下のように書いてあります。

extern int printf(const char* ...);

(printf関数は、第1引数の文字列に含まれる変換指定子の数によって引数の数が変わるので、定義やプロトタイプ宣言が特殊な形をしています。)

これを #include プリプロセッサーでCプログラムに読み込むことによって、printf関数が使えるようになります。

/*
 *  Hello World!
 */
#include <stdio.h>

int main(void) {
  printf("Hello World!\n");
  return 0;
}

< >と" "

C言語には標準でいくつかのヘッダー・ファイルが用意してあります。

標準で用意されているヘッダー・ファイルは、ヘッダー・ファイルの名前を不等号の括弧 < > で囲んで指定します。

ヘッダー・ファイルは、自分で用意することもできます。

自分で用意したヘッダー・ファイルは、ヘッダー・ファイルの名前をダブル・クォーテーション " " で囲んで指定します。

例えば、次のようなプログラムとヘッダー・ファイルを用意します(プログラム1a, 1b)。

/*
 *  add.c: 和を求める
 */
double add(double x, double y) {
  return x + y;
}
/*
 *  add.h
 */
extern double add(double, double);

このヘッダー・ファイルを読み込むには、ファイル名をダブル・クォーテーション " " で囲んで、次のように指定します(プログラム1c)。

/*
 *  main.c: 和を求めて出力する
 */
#include <stdio.h>
#include "add.h"

int main(void) {
  double x = 1.0, y = 2.0;
  double z = add(x, y);
  printf("%f\n", z);
  return 0;
}

main.c をコンパイルすると、プリプロセッサーによって add.h が読み込まれてから翻訳が行われます。

演習1

プログラム1a, 1b, 1cを作成し、コンパイルせよ。

マクロ定義

#define

#define はマクロ定義を置換するプリプロセッサーです。

#define マクロ名 文字列

注意点

マクロ定義は、単に置換されるだけなので、置換後にどうなるかに注意する必要があります。

たとえば、次のプログラムについて考えてみましょう。

/*
 *  二次元配列を宣言し、すべての要素に0を代入する
 */
#include <stdio.h>

#define N    4

int main(void) {
  int a[N][N];
  int i, j;

  for (i = 0; i < N; i++) {
    for (j = 0; j < N; j++) {
      a[i][j] = 0;
    }
  }

  return 0;
}
/*
 *  キーボードから0-3を入力すると、(0, 0)から対応する方向へ1マスずつ進む
 */
#include <stdio.h>

#define NORTH    0
#define EAST     1
#define WEST     2
#define SOUTH    3

int main(void) {
  int x = 0, y = 0, f = 0;

  while (1) {
    printf("0-3のいずれかを入力してください:\n");
    scanf("%d", &dir);

    switch (dir) {
    case NORTH:
      y++;
      break;
    case EAST:
      x++
      break;
    case WEST:
      x--;
      break;
    case SOUTH:
      y--;
      break;
    default:
      f = 1;
    }

    if (f) { break; }
    printf("(%d, %d)へ移動しました\n");
  }

  return 0;
}

main関数だけを見ると、Xの2倍を求めています。

このプログラムをコンパイルすると、まず、マクロ定義 X が 1 + 1 に置き換えられます。 したがって、前処理が行われ、実際に翻訳されるプログラムは次のようになります。

enum { NORTH, EAST, WEST, SOUTH };

X が 1 + 1 に置き換えられ、式が 1 + 1 * 2 になりました。 すると、加算演算子 + よりも乗算演算子 * の方が優先順位が高いので、計算結果は X の2倍の 4 ではなく、3 になってしまいます。

まとめ

前処理(プリプロセッサー)には、主に、ヘッダー・ファイルの読み込み (#include) と、マクロ定義の置換 (#define) があります。

Cプログラムをコンパイルすると、前処理が行われてから、翻訳が行われます。

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS