私はいくつかのC宣言を理解しようとしています。これらの C 宣言の意味は何ですか?
double (*b)[n];
double (*c[n])();
double (*d())[n];
私はいくつかのC宣言を理解しようとしています。これらの C 宣言の意味は何ですか?
double (*b)[n];
double (*c[n])();
double (*d())[n];
double (*b)[n];
b は、n 個の double の配列へのポインターです。
double (*c[n])();
c は、指定されていない数の引数を取り、double を返す関数への n 個のポインターの配列です。
double (*d())[n];
d は、指定されていない数の引数を取り、n 個の double の配列へのポインターを返す関数です。
一般に、この種の宣言を頭の中で解析するには、次のアプローチを取ります。たとえば、最後の宣言を見てみましょう
double (*d())[n];
d に対して最初に行われることは何ですか? () で呼び出されるので、不特定多数の引数を取って returnig を返す関数です。結果はどうなりますか? 逆参照 (*) されているため、 へのポインターです。次に、結果にインデックスが付けられるため、n の配列になります。何が残るでしょうか。double、したがってdoublesの。太字の部分を読むと、答えが得られます。
別の例を見てみましょう
void (*(*f)(int)[n])(char)
ここでは、f が最初に逆参照されるため、これは...へのポインターであり、次に (int) で呼び出されます。したがって、関数は int を取り、 を返します。結果は [n] でインデックス付けされるため、 n の配列になります。結果は再び逆参照されるため、 . 次に、結果は (char) によって呼び出されるため、関数は char を受け取り、(残っているものはすべて void) voidを返します。したがって、 f はint を取り、 char を取り void を返す関数への n 個のポインタの配列を返す関数へのポインタです。
HTH
C 宣言を解析するための基本的なルールは、「右から左に読み取り、括弧のペアを離れるときは裏返しに右にジャンプする」です。つまり、最も深くネストされた括弧のペアを開始し、右に向かって自分自身を調べます。技術的には、演算子の結合性を知っている必要がありますが、ほとんどの状況では十分に機能します。
この(簡略化された)ルールを質問に適用しましょう:
double (*b)[n]; ^
b は
double (*b)[n]; ^
へのポインタ
double (*b)[n]; ^^^
と配列
double (*b)[n]; ^^^^^^
ダブルスの。
double (*c[n])(); ^^^^
cはの配列です
double (*c[n])(); ^
へのポインタ
double (*c[n])(); ^^
機能
double (*c[n])(); ^^^^^^
倍返し。
double (*d())[n]; ^^^
d は関数です
double (*d())[n]; ^
へのポインタを返す
double (*d())[n]; ^^^
の配列
double (*d())[n]; ^^^^^^
ダブルス
ほとんどの *nix には、C 宣言文字列を取り、それを自然言語文に変換するcdeclと呼ばれる便利なユーティリティがあります。
この方法で試してみましょう。
まず、次の 3 つの記号に慣れておく必要があります。
1. * -- ポインター。 2. [] -- 配列。 3. () -- 関数。(注意: 括弧ではありません)
例として「double (*d())[n]」を取り上げます。
最初のステップは、宣言内の識別子を見つけることです。識別子は変数の名前です。ここでは「d」です。
(私) --「d」とは何ですか? -------------------------------------------------- ---------------------- 識別子の右側を見て、「[]」または「()」があるかどうかを確認します。 ...d[]...: d は配列です。 ...d()...: d は関数です。 どちらでもない場合は、左側に「*」があるかどうかを確認します。 ...*d...: d はポインタです。 -------------------------------------------------- ----------------------
これで、d が関数であることがわかりました。x を使用して d() を置き換えると、宣言は「double (*x)[n]」になります。
(ⅱ) ――「×」とは? -------------------------------------------------- ---------------------- (i) を繰り返すと、x がポインターであることがわかります。 つまり、d はポインタを返す関数です。 -------------------------------------------------- ----------------------
y を使用して *x を置き換えると、宣言は「double y[n]」になります。
(ⅲ) - Yとは何ですか"? -------------------------------------------------- ---------------------- (i) を繰り返すと、y が n 要素の配列であることがわかります。 つまり、d は n 要素の配列へのポインタを返す関数です。 -------------------------------------------------- ----------------------
z を使用して y[n] を置き換えると、宣言は「double z」になります。
(四) -- 「z」とは何ですか? -------------------------------------------------- ---------------------- (i) を繰り返すと、z が double であることがわかります。 つまり、d は、n 個の double 要素の配列へのポインターを返す関数です。 -------------------------------------------------- ----------------------
別の表現を見てみましょう:
ボイド (*(*f)(int)[n])(char)
1. f を見つけます。 2. f はポインタです。*f -> a void (*a(int)[n])(char) 3. a は関数です。a() -> b ボイド (*b[n])(文字) --f は関数へのポインターです (int パラメーターを使用)-- 4. b は配列です。b[] -> c ボイド (*c)(文字) --f は (n 要素の) 配列を返す関数へのポインタです -- 5. c はポインタです。*c -> d ボイド d(文字) --f は、n 個のポインタの配列を返す関数へのポインタです-- 6. d は void を返す関数です。 --f は、void を返す関数 (char パラメータ付き) への n 個のポインタの配列を返す関数へのポインタです--
「C 意味不明」を理解するには、次の 2 つの優れたリソースがあります。
cdecl.org の出力:
double (*c[n])()
: 構文エラー (n
ここでは無効です)double (*c[])()
: double を返す関数へのポインタの配列として c を宣言します