インターネットでいくつかのコードを調べていたところ、次のことがわかりました。
float * (*(*foo())[SIZE][SIZE])()
この宣言の読み方は?このような複雑な宣言を読み取るための特定のルール セットはありますか?
インターネットでいくつかのコードを調べていたところ、次のことがわかりました。
float * (*(*foo())[SIZE][SIZE])()
この宣言の読み方は?このような複雑な宣言を読み取るための特定のルール セットはありますか?
私はしばらくこれをしていません!
から始めてfoo
、右に進みます。
float * (*(*
foo()
)[SIZE][SIZE])()
foo は引数のない関数です...
閉じ括弧があるのでうまくいきません。左に移動:
float * (*(
* foo()
)[SIZE][SIZE])()
foo はポインタを返す引数のない関数です
これ以上左に行けないので 括弧をまたいで右に行きましょう
float * (*
(* foo())
[SIZE][SIZE])()
float * (*
(* foo())[SIZE]
[SIZE])()
float * (*
(* foo())[SIZE][SIZE]
)()
foo は、SIZE ... の SIZE 配列の配列へのポインタを返す、引数のない関数です。
閉じ括弧に到達し、ポインター記号に到達するために再び左に移動しました:
float * (
*(* foo())[SIZE][SIZE]
)()
foo は、 ... への SIZE ポインターの SIZE 配列の配列へのポインターを返す、引数のない関数です。
再び左括弧なので、それをまたいで右に進みます。
float *
( *(* foo())[SIZE][SIZE])
()
float *
( *(* foo())[SIZE][SIZE])()
foo は、引数のない関数への SIZE ポインターの SIZE 配列の配列へのポインターを返す引数のない関数です...
そして最後まで残した
float * ( *(* foo())[SIZE][SIZE])()
foo は SIZE 配列の配列へのポインタを返す引数のない関数です float へのポインタを返す引数のない関数への SIZE ポインタ
そして、それを書いた人は誰でも、彼に使い方を教えてくださいtypedef
:
// Function that returns a pointer to float
typedef float* PFloatFunc ();
// Array of pointers to PFloatFunc functions
typedef PFloatFunc* PFloatFuncArray2D[SIZE][SIZE];
// Function that returns a pointer to a PFloatFuncArray2D
PFloatFuncArray2D* foo();
標準的なルール:左端の識別子を見つけて、それを覚えて前[]
に()
バインドして*
ください。
foo -- foo
foo() -- is a function
*foo() -- returning a pointer
(*foo())[SIZE] -- to a SIZE-element array
(*foo())[SIZE][SIZE] -- of SIZE-element arrays
*(*foo())[SIZE][SIZE] -- of pointers
(*(*foo())[SIZE][SIZE])() -- to functions
* (*(*foo())[SIZE][SIZE])() -- returning pointers
float * (*(*foo())[SIZE][SIZE])(); -- to float
したがって、ポインタを返す関数がたくさんあると想像してくださいfloat
。
float *quux();
float *bar();
float *bletch();
float *blurga();
それらを2x2テーブルに保存するとします。
float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga};
tab
にポインタを返す関数へのポインタのSIZExSIZE配列ですfloat
。
次に、関数がそのテーブルへのポインタを返すようにすることを決定しましょう。
float *(*(*foo())[SIZE][SIZE])()
{
static float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga};
return &tab;
}
異なる関数のテーブルを作成したり、同じ関数を異なる方法で編成したりする複数の関数を使用できることに注意してください。
float *(*(*qwerbl())[SIZE][SIZE])()
{
static float *(*tab[SIZE][SIZE])() = {blurga, bletch, bar, quux};
return tab;
}
これが私がこのようなことをすることを考えることができる唯一の理由です。このようなタイプは、野生ではあまり見られないはずです(ただし、ときどき発生し、同様に凶悪なものを書いたことで罪を犯しました)。
cdecl.orgによると
foo を配列へのポインタを返す関数として宣言する 配列の SIZE 関数へのポインタの SIZE float へのポインタを返す
手で解読したい場合は、Lukian Grigore によって与えられたスパイラル ルールを使用します。
ここで行う最善の方法は、一連の typedef に変換することです。
typedef float * fnReturningPointerToFloat();
typedef fnReturningPointerToFloat* fnArray[SIZE][SIZE];
fnArray* foo();
通常、cdecl.orgを試すことができますが、代わりにSIZE
12を交換SIZE
すると、次のようになります。
float へのポインターを返す関数へのポインターの配列 12 の配列 12 へのポインターを返す関数として foo を宣言する
それが本当にあなたを助けるかどうかはわかりません!
ここでの2つの観察:
このドキュメントは、C 宣言を簡単に準備する方法についての最良の手がかりを与えてくれました。
http://c-faq.com/decl/spiral.anderson.html
次の 3 つの簡単な手順に従います。
未知の要素から始めて、らせん/時計回りの方向に移動します。次の要素に遭遇した場合、それらを対応する英語のステートメントに置き換えます。
[X]
または[]
=> 配列 X サイズ ... または 配列未定義サイズ ...
(type1, type2)
=> type1 を渡す関数と type2 を返す関数 ...
*
=> ...へのポインタすべてのトークンが覆われるまで、これをスパイラル/時計回りの方向に続けます。
括弧内は常に最初に解決してください。
例 :
+-------+
| +-+ |
| ^ | |
char *str[10];
^ ^ | |
| +---+ |
+-----------+
Question we ask ourselves: What is str?
``str is an...
- We move in a spiral clockwise direction starting with `str' and the first character we see is a `[' so, that means we have an array, so...
``str is an array 10 of...
- Continue in a spiral clockwise direction, and the next thing we encounter is the `*' so, that means we have pointers, so...
``str is an array 10 of pointers to...
- Continue in a spiral direction and we see the end of the line (the `;'), so keep going and we get to the type `char', so...
``str is an array 10 of pointers to char''
We have now ``visited'' every token; therefore we are done!
foo を配列へのポインタを返す関数として宣言する 配列の SIZE 関数へのポインタの SIZE float へのポインタを返す