ルールは正しいです。ただし、適用には細心の注意を払う必要があります。
C99+ の宣言には、より正式な方法で適用することをお勧めします。
ここで最も重要なことは、すべての宣言の次の再帰構造を認識することです ( const
、volatile
、static
、extern
、inline
、は、struct
簡単にするために図から削除されていますが、簡単に追加し直すことができます)。union
typedef
base-type [derived-part1: *'s] [object] [derived-part2: []'s or ()]
はい、以上です、4 つの部分です。
where
base-type is one of the following (I'm using a bit compressed notation):
void
[signed/unsigned] char
[signed/unsigned] short [int]
signed/unsigned [int]
[signed/unsigned] long [long] [int]
float
[long] double
etc
object is
an identifier
OR
([derived-part1: *'s] [object] [derived-part2: []'s or ()])
* is *, denotes a reference/pointer and can be repeated
[] in derived-part2 denotes bracketed array dimensions and can be repeated
() in derived-part2 denotes parenthesized function parameters delimited with ,'s
[] elsewhere denotes an optional part
() elsewhere denotes parentheses
4 つの部分をすべて解析したら、
[ object
] は [ derived-part2
(含む/返す)] [ derived-part2
(へのポインター)] base-type
1です。
再帰がある場合、(ある場合) 再帰スタックの一番下にあるものを見つけますobject
。それは最も内側のものであり、戻って各レベルで派生部分を収集して結合することにより、完全な宣言を取得します。再帰の。
解析中は、 (もしあれば) [object]
after に移動できます。[derived-part2]
これにより、線形化されたわかりやすい宣言が得られます (上記の1を参照)。
したがって、
char* (**(*foo[3][5])(void))[7][9];
あなたが得る:
base-type
=char
- レベル 1:
derived-part1
= *
、object
= (**(*foo[3][5])(void))
、derived-part2
=[7][9]
- レベル 2:
derived-part1
= **
、object
= (*foo[3][5])
、derived-part2
=(void)
- レベル 3:
derived-part1
= *
、object
= foo
、derived-part2
=[3][5]
そこから:
- レベル3:
*
[3][5]
foo
- レベル2:
**
(void)
*
[3][5]
foo
- レベル1:
*
[7][9]
**
(void)
*
[3][5]
foo
- 最後に、
char
*
[7][9]
**
(void)
*
[3][5]
foo
さて、右から左に読んでください:
foo
関数への 5 つのポインターの 3 つの配列の配列 (パラメーターをとらない) は、char への 9 つのポインターの 7 つの配列の配列へのポインターを返します。
derived-part2
プロセスのすべてで配列の次元を逆にすることもできます。
それがあなたのスパイラルルールです。
そしてスパイラルが見やすい。左からさらに深くネストされたものに飛び込み[object]
、次に右に再浮上して、上のレベルに別の左と右のペアがあることに注意してください。