「C言語」の「マクロ」「プロプロセッサ」「列挙型」を学ぶ

「C言語」を利用する際に必要な「マクロ」「プリプロセッサ」について、どのような機能なのかを学んでいきたいと思います。

意味がよくわからず、「このように書いたらいい」という「おまじない」を書くような学習状態では、本当に「C言語」を理解しているとは言えません。

主要な機能については一通り学んだかなと思っているので、まだ学んでいない機能や「うる覚え」の機能について学んでいきたいと思います。

「マクロ」の機能と種類

「マクロ」という難しそうな名前から、「複雑な機能なんだろうな~」と勝手に思っていたのですが、単に「プログラム内の文字列を置換する」機能なようです。

ただ、「マクロ」を実行するためには、「プリプロセッサ」について理解する必要があります。

プリプロセッサ

「プリプロセッサ」という言葉の意味は「コンパイル」の前に行う「処理」のことを言うそうです。

「コンパイル」ってそもそも何だっけ・・・

といろいろと調べてみると、「ソースコード」を「機械語」に変換することでした。

以前に学んだけど、忘れてしまってた・・・

コンパイルイメージ

この「プリプロセッサ」を利用して、「マクロ」を作るみたいなのですが、その際に「#define」というプリプロセッサを利用するとのこと。

そして、「マクロ」には、

  • 値を扱えるマクロ
  • 関数を扱えるマクロ

の2種類を作ることができます。

「マクロ」の作り方

まず、「値」を定義する「マクロ」を作るためには、

#define マクロ名 値; 

のように書いていきます。

例えば、

#include <stdio.h>
#define MAX_NUM 5

int main(void) {

    int i;

    for(i = 0; i< MAX_NUM; i++){

        printf("num=%d\n", i);

    }

    return 0;
}

と書くと、マクロで設定した値を変数を利用するのと同じように利用することができますね。

ただし、マクロは変数では無いので、「代入演算子」で値を変更することはできません。

プリプロセッサの働きで、プログラムに埋め込まれた「MAX_NUM」の文字が「5」に変換されてからコンパイルされる仕組みとなっています。

なので、コンパイルが終わると、そこには単純に「5」という値が存在しているだけなんですね。

では「関数」を利用したマクロについても見ていきたいと思います。

マクロを関数として使うと、

#include <stdio.h>
#define MAX_NUM 10
#define MULTI_TWO(num)(num%2==0?1:0)

int main(void) {

    int i;

    for(i = 1; i <= MAX_NUM; i++){

        printf("num=%d", i);

        if(MULTI_TWO(i) == 1){
            printf("(2の倍数)");
        }
        printf("\n");
    }

    return 0;
}

「MULTIPLE OF TWO(2の倍数)」かどうかを判定できる機能をマクロにしてみました。

「for」文の中の「if」文で、「MULTI_TWO」というマクロを利用して、「2の倍数」という文字列を出力するかを判定していますね。

マクロを使うことのメリットって何なんだろう??

と思って調べてみると、「関数を呼び出すような複雑な処理を回避し処理の時間を短縮できる」とありましたが、あんまりメリットに感じられなかったのと、デメリットも思ったより多いことがわかりました。

デメリットとしては、単に「文字の置き換え」を行っているため、何回も使うと、「コードの重複が発生する」といったことや、「データ型のチェック」が行われないということがあるみたいです。

結局のところ、どうやって使えばいいのかわからなかったのですが、「どのような機能なのか?」は理解できた気がします。

列挙型

「列挙型」は「定数」を「配列のように扱える仕組み」みたいなのですが、「列挙型」の使い方について学んでいきたいと思います。

列挙型の作り方1>

「列挙型」を作るためには、

euum タグ名 {定数名1 = int型の値, 定数名2 = int型の値,・・・・};

のように書いていく必要があります。

プログラムを書いてみると、

#include <stdio.h>

int main(void) {

    enum FoodType { FRUITS = 1, VEGETABLE = 2, MEET = 3 };

    enum FoodType ft = MEET;

    printf("FoodType=%d", ft);

    return 0;
}

のようになりますが、列挙型は「名前(定数名)」と「値」を割り当てていくことができる機能のようですね。

このプログラムの実行結果は、

FoodType=3

のようになります。

単に数値で表現するよりも「人間が見てわかりやすい文字」」に置き換えることができるので、プログラムの内容がわかりやすくなるというメリットがありそうです。

列挙型で付けている名前は「列挙定数」とも呼ばれています。

列挙型の作り方2

もう一つの列挙型の作り方には、

typedef enum{
    定数名1 = int型の値,
    定数名2 = int型の値,
             ・
             ・
             ・
} タグ名;

のように書く方法もあります。

この書き方を利用して、さきほどの「FoodType」列挙型を作ってみると、

#include <stdio.h>

int main(void) {

    typedef enum {
        FRUITS = 1,
        VEGETABLE = 2,
        MEET = 3
    } FoodType;


    printf("FoodType FRUITS=%d", FRUITS);

    return 0;
}

のようになります。

列挙型の使いどころを知るためにはもっといろいろなプログラムを書いていかないと、実感として列挙型のメリットを感じることは難しそうですね。

今後ももっといろいろなコードをプログラミングしながら「列挙型の使いどころ」を探していきたいと思います。

→(前へ)「ポインタ」の仕組みと使い方を学んでみる

→(次へ)「C言語」の「ファイル操作の仕組み」とプログラムの書き方を学ぼう!

→「Twitter:@satoru78888」

HOMEへ