「スパイラル」ルールは、次の優先ルールには含まれていません。
T *a[] -- a is an array of pointer to T
T (*a)[] -- a is a pointer to an array of T
T *f() -- f is a function returning a pointer to T
T (*f)() -- f is a pointer to a function returning T
添え字演算子[]と関数呼び出し()演算子は、単項よりも優先順位が高い*ため、*f()として解析され*(f())、*a[]として解析され*(a[])ます。
したがって、配列へのポインターまたは関数へのポインターが必要な*場合は、(*a)[]またはのように、を識別子で明示的にグループ化する必要があります(*f)()。
次に、それを認識しa、f単なる識別子よりも複雑な式にすることができます。in T (*a)[N]、a単純な識別子、または(*f())[N](a-> f())のような関数呼び出し、または(*p[M])[N](a-> p[M])のような配列、または(*(*p[M])())[N](a-> (*p[M])())のような関数へのポインターの配列等
間接演算子*が単項ではなく後置演算子であると、宣言が左から右にいくらか読みやすくなります(void f[]*()*();間違いなくよりもフローがよくなりますvoid (*(*f[])())())が、そうではありません。
そのような毛深い宣言に遭遇したとき、左端の識別子を見つけて、上記の優先規則を適用し、それらを任意の関数パラメーターに再帰的に適用することから始めます。
f -- f
f[] -- is an array
*f[] -- of pointers ([] has higher precedence than *)
(*f[])() -- to functions
*(*f[])() -- returning pointers
(*(*f[])())() -- to functions
void (*(*f[])())(); -- returning void
signal標準ライブラリの関数は、おそらくこの種の狂気の型標本です:
signal -- signal
signal( ) -- is a function with parameters
signal( sig, ) -- sig
signal(int sig, ) -- which is an int and
signal(int sig, func ) -- func
signal(int sig, *func ) -- which is a pointer
signal(int sig, (*func)(int)) -- to a function taking an int
signal(int sig, void (*func)(int)) -- returning void
*signal(int sig, void (*func)(int)) -- returning a pointer
(*signal(int sig, void (*func)(int)))(int) -- to a function taking an int
void (*signal(int sig, void (*func)(int)))(int); -- and returning void
この時点で、ほとんどの人は「use typedefs」と言っていますが、これは確かにオプションです。
typedef void outerfunc(void);
typedef outerfunc *innerfunc(void);
innerfunc *f[N];
だが...
式でどのように使用 fしますか?あなたはそれがポインタの配列であることを知っていますが、正しい関数を実行するためにどのように使用しますか?typedefを調べ、正しい構文を理解する必要があります。対照的に、「ネイキッド」バージョンはかなり目立たないですが、式での使用 方法を正確に示しますf(つまり、(*(*f[i])())();どちらの関数も引数を取らないと仮定して)。