スパゲッティ・クイズ

C99。ポインタ自体が変更できないのはどれでしょうか。

(1) int *const x;
(2) int const *x;
(3) const int *x;

一行目の f と同じ型を持つのはどれでしょうか。

    int f(int *x[2][3]);
(1) int g(int *x[2][2]);
(2) int g(int *x[3][3]);
(3) int g(int ***x);

同じく、一行目の f と同じ型を持つのは。

    int f(int (*x)(short y));
(1) int g(int x());
(2) int g(int x(short));
(3) int g(int *x(short));

f()(123) という呼び出しが可能なのはどれ。

(1) int (*f())();
(2) int (*f(int))();
(3) int (*f())(void);

宣言されている各識別子の型と、宣言 (1), (2) の意味は。

int main(void) {
  const typedef int *a[123];
  int typedef unsigned *(*f(const a))(void (), int (*(*)())[]);
  { f f; }        // (1)
  { f const f; }  // (2)
}


(1)、(2)、(2)、(1)。関数の仮引数では、(最外の)配列や関数はポインタに読み替えられる(だから、二問目の f では 2 という値には意味がない)。また、関数の(定義ではない)宣言で f() のように引数を何も書かないと、引数を取らないという意味ではなく、引数に関する情報が利用できないことを示す(前者の意味では f(void) のように書く)。
最後のは、main は引数なしで int を返す関数、aconst int へのポインタが 123 個並んだ配列。fconst int への const ポインタへのポインタを取って関数ポインタを返す関数で、返却される関数は、引数が未知で返り値のない関数へのポインタと、引数が未知で int の長さ不明の配列へのポインタを返す関数へのポインタを受け取り、unsigned int へのポインタを返す。(1)f 型を持つ f という名前の関数を宣言する。関数型を修飾しようとしている (2) の効果は、なぜか未定義である。