C の宣言は複雑になってしまうことが多々あります。関数へのポインタやその引数にまた関数へのポインタがあったりすると、もうお手上げです。しかし、このような複雑な C の宣言を簡単に読み解ける right-left rule というものがあるので 5 つの例を通して紹介したいと思います。
int *p[5]
まずは、本当に簡単な例から。right-left rule は、最初に変数の名前から読み始めます。ここでは、p です。そして、右へ左へと繰り返して読みます。この int *p[5] の例であれば、
1 2 3 4 | p[5] /* p は 5 つの ”何かの” 要素を持つ配列 */ *p[5] /* p は 5 つの ”何かの” 要素へのポインタを持つ配列 */ *p[5] /* [5] の右には何もないので、左へ */ int *p[5] /* p は 5 つの int 要素へのポインタを持つ配列 */ |
このルールを適応すれば難しい宣言での読み解けます。
int (*f) (int i)
先ほどのルールにもう 1 つだけルールを加えます。それは、変数名のまわりの括弧は先に終わらせるということです。この例で言えば、(*f) を先に読み終えるということです。では、見ていきます。
1 2 3 4 | (f) /* 括弧内の右には何もないので左へ */ (*f) /* f は “何かの” ポインタ */ (*f)(int i) /* f は int を引数に持つ関数へのポインタ */ int (*f)(int i) /* f は int を引数に持ち、int を返す関数へのポインタ */ |
int (*p)[20]
2 つ目の例と同じように変数名のまわりの括弧を終わらせます。そして、純粋に右左右左を繰り返します。
1 2 3 4 | (p) /* 括弧内の右には何もないので左へ */ (*p) /* p は “何かの” ポインタ */ (*p)[20] /* p は 20 つの “何かの” 要素を持つ配列へのポインタ */ int (*p) [20] /* p は 20 つの int 要素を持つ配列へのポインタ */ |
1 つ目の例とこの 3 つ目例は見た目が似ているのに大きく異なりますね。1 つ目は、20個の int へのポインタを持つ配列。2 つ目は、たった 1 つのポインタです。
int (*f[5])(float f)
この辺りから個人的にキツイ。
1 2 3 4 | (f[5]) /* f は 5 つの “何かの” 要素を持つ配列 */ (*f[5]) /* f は 5 つの “何かの” ポインタを持つ配列 */ (*f[5])(float f) /* f は float 引数を持つ関数へのポインタ 5 つを持つ配列 */ int (*f[5])(float f) /* f は、float 引数を持ち、int を返す関数へのポインタ 5 つを持つ配列 */ |
こいつが配列には見えない。
int (*func(int num)) (int)
関数へのポインタを返す関数です。
1 2 3 4 | (func(int num)) /* func は int 引数を持つ関数 */ (*func(int num)) /* func は int 引数を持ち、”何かへの” ポインタを返す関数*/ (*func(int num))(int) /* func は int 引数を持ち、"int 引数を持つ関数への” ポインタを返す関数*/ int (*func(int num))(int) /* func は int 引数を持ち、”int 引数を持ち、int を返す関数への” ポインタを返す関数*/ |
もうむちゃくちゃですね。簡単には読み解けませんでした。