C言語の演算子の優先順位はけっこう複雑な方だとおもう。

宣言の読み方が難しいのは宣言に出てくる演算子の優先度がわかりにくいのもあるが、ポインタのデリファレンス演算子 * が前置演算子になっているのが原因だとおもう。他の演算子 関数呼び出しの ()・配列アクセスの [] は後置演算子で、ポインタの * よりも優先度が高いのでポインタ演算子を先に効かせたい場合に括弧が必要になって見た目が複雑になる。

void (*(*f[])())() の読み方

f は変数
f[] fは配列
*f[] 配列の要素はポインタ
(*f[])() ポインタは関数を指している
*(*f[])() 関数はポインタを返す
(*(*f[])())() 返ってきたポインタは関数を指している
void (*(*f[])())() 関数の戻り値はvoid

仮にポインタデリファレンスが前置 の * ではなくて後置の @ だとしたらどうなるか。

void (*(*f[])())()

void f[]@()@()

と書けて、最初の型以外は左から右に直線的に読むだけで済む。

IMG_20180606_001314