C言語入門 第16回 関数宣言(新旧)とvoid型




2014年10月より個人の方を対象に、Study C無料提供を開始しました。
C言語を勉強中の方は、学習・教育に最適なC言語インタープリタのStudy Cを使ってみてください(個人の方は無料です)。
大学・高専・高校などの教育機関での採用実績も多数あるロングセラー商品Study Cが、個人向けに無料提供を始めました。
インタープリタの手軽さに加え、ゲームや3Dタートルグラフィックで楽しく勉強したりと、C言語の学習を強力にサポートします。
ブロック崩しゲーム 3Dツリー クリスマスツリー
また、このようなボタンの用意されているページでは、掲載しているプログラムをStudy Cに直接ロードし実行したりすることができます。
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する
Study C無料利用についての詳細は、このページを参照してください。



1.ANSI規格(関数宣言)

 C言語にはANSIで取り決められている新しい規格と、カーニハンとリッチーが最初に取り決めた古い規格が存在します。 ANSI規格は古い規格に機能を追加していくような形で拡張されているため、古い規格で書かれているプログラムも問題なくコンパイルすることができます。 古いソースが残ってることもあるかもしれないので、一応知っておいた方が良いと思います()。

2.関数宣言(新旧)

 関数の宣言方法に新しい形式のものが追加されました。 パラメータの型が関数名直後のカッコ内で宣言することがでるようになりました。

        古い規格                        新しい規格

        func(a, b)                      func(int a, int b)
        int a, b;                       {
        {                                       .
              .                                 .
              .                         }
        }

        func1(a, b)                     func1(int a, long b)
        int a;                          {
        long b;                                 .
        {                                       .
              .                         }
              .
        }

        usr_strlen(p)                   usr_strlen(char *p)
        char *p;                        {
        {                                       .
              .                                 .
              .                         }
        }

 ANSI規格では関数ごとに両方の規格を混在していても構いませんが、次のような宣言はエラーとなります。

func(int a, b)
int b;
{
        .
        .
}

ANSI規格の関数宣言を使用しているプログラムを古い規格の関数宣言に変更する場合は、次のように行います。

@小カッコ内の宣言を右小カッコ())と左中カッコ({)の間にコピーします。
      例)
        func(int a, long b)             func(int a, long b)
        {                               int a, long b
              .               →        {
              .                               .
        }                                     .
                                        }

Aコピーした部分のカンマ(,)をセミコロン(;)に変更し、最後にもう1つ
      セミコロン(;)を追加します。
      例)
        func(int a, long b)             func(int a, long b)
        int a, long b                   int a; long b;
        {                               {
              .               →              .
              .                               .
        }                               }

B括弧内の変数名とカンマ(,)以外の文字を削除します。
      例)
        func(int a, long b)             func(a, b)
        int a; long b;                  int a; long b;
        {                               {
              .               →              .
              .                               .
        }                               }

3.関数のパラメータチェック

 C言語の多くのコンパイラは基本的にパラメータのチェックを行いません。たとえば、次のようなプログラムは何のエラーも発生せずにコンパイラで翻訳されますが、正常には動作しません。

main()
{
        func(1);
        .
        .
}

func(a, b)
int a, b;
{
        .
        .
}

 Study Cでは関数のパラメータをチェックするのでfunc(1);の行でエラーが発生しますが、コンパイラではこの種のエラーチェックを行いません。 このためANSI規格では、次のような宣言(プロトタイプ宣言)を追加することでパラメータのチェックを行うようになりました。

int   func(int, int);

このようなプロトタイプ宣言をプログラムの最初で行うと、それ以降のfunc()関数呼出し時にパラメータの個数や型が正しいかをコンパイラがチェックしてくれます。 しかし、古い規格ではプロトタイプ宣言が使用できないので、パラメータのチェックをコンパイラに行わせることができません(Study Cではプロトタイプ宣言がなくても常にパラメータのチェックを行います)。

4.void型関数

関数は、return(...)によって値を返しますことができます。 そのような場合は、int型などの関数として定義します。

int     func()
{
        ...
        return(123);
}

main()
{
        func();
}

しかし全ての関数が返す必要があるわけではありません。次の例ではfunc関数は値を返していません。

func()
{
        ...
}

main()
{
        func();
}

このままでもエラーにはなりませんが(エラーにするコンパイラもあるかもしれません)、このような関数はvoid型の関数として宣言します。 void型宣言に書き換えると次のようになります。

void    func()
{
        ...
}

main()
{
        func();
}

void型宣言にすると呼び出し側が関数の返値を参照しようとしたり、void型関数内で値を返そうとするとコンパイラ(やインタープリタ)がエラーとして検出してくれるようになります。

5.プロトタイプ宣言とvoid型

関数が引数を持つ場合は、以下のようにプロトタイプ宣言をおこないます。

int     func(int, int); ← プロトタイプ宣言

main()
{
        func();
}

int     func(int a, int b)
{
        ...
        return(...);
}

引数が存在しない関数のプロトタイプ宣言にもvoidが使用されます。 引数のない関数のプロトタイプ宣言は次のようになります。

int     func(void);     ← プロトタイプ宣言

main()
{
        func();
}

int     func()
{
        ...
        return(...);
}