プログラミング
C言語の「時計回り/スパイラルルール」
The C ``Clockwise/Spiral Rule'' (c-faq.com)
要約
C言語の宣言を解析するための「時計回り/スパイラルルール」というテクニックが紹介されています。このルールは、未知の要素から時計回りにスパイラル状に進みながら、遭遇する記号(配列 `[]`、ポインタ `*`、関数 `()`)を特定の英語の定義に置き換えていくことで、複雑な宣言も頭の中で理解できるようにします。例を複数用いて、その適用方法が解説されています。
全文翻訳
(これは、作者である David Anderson が 1994-05-06 に comp.lang.c に投稿したものです。)
「時計回り/スパイラルルール」
David Anderson 著
「時計回り/スパイラルルール」として知られるテクニックがあります。これは、あらゆるCプログラマーが頭の中で任意のC宣言を解析できるようにするものです!
従うべき簡単な3つのステップがあります:
未知の要素から始め、スパイラル/時計回りの方向に移動します。以下の要素に遭遇したら、対応する英語のステートメントに置き換えます:
[X] または [] => サイズ X の配列... または サイズ未定義の配列...
(type1, type2) => type1 と type2 を渡して... を返す関数
* => ...へのポインタ
すべてのトークンがカバーされるまで、スパイラル/時計回りの方向にこれを続けます。常に括弧内のものを先に解決してください!
例1:簡単な宣言
char *str[10];
私たちが自問する質問:strとは何ですか?
「str は...」
str から始めてスパイラル時計回りの方向に移動すると、最初に見るのは `[` です。これは配列を意味するので...
「str はサイズ 10 の配列で...」
スパイラル時計回りの方向に続け、次に遭遇するのは `*` です。これはポインタを意味するので...
「str はサイズ 10 のポインタで、...へのポインタ」
スパイラル方向に続け、行末(`;`)を見ますが、まだすべてのトークンを訪れていません。続行すると、型 `char` に到達します。したがって...
「str はサイズ 10 のポインタで、char へのポインタ」
これで全てのトークンを「訪問」しました。したがって、完了です!
例2:関数へのポインタ宣言
char *(*fp)( int, float *);
私たちが自問する質問:fpとは何ですか?
「fp は...」
スパイラル時計回りの方向に移動すると、最初に見るのは `)` です。したがって、fp は括弧内にあります。括弧内をスパイラルで続行すると、次に見た文字は `*` です。
「fp は ... へのポインタ」
これで括弧の外に出ました。スパイラル時計回りに続行すると、`(` が見えます。したがって、関数です。
「fp は、int と float ポインタを渡して... を返す関数へのポインタ」
スパイラル方向に続行すると、次に `*` 文字が見えます。
「fp は、int と float ポインタを渡して、... へのポインタを返す関数へのポインタ」
スパイラル方向に続行すると、`;` が見えますが、すべてのトークンを訪問していません。続行すると、型 `char` に到達します。
「fp は、int と float ポインタを渡して、char へのポインタを返す関数へのポインタ」
例3:「究極の」宣言
void (*signal(int, void (*fp)(int)))(int);
私たちが自問する質問:「signal」とは何ですか?
signal が括弧内にあることに注意してください。したがって、これを最初に解決する必要があります!
時計回りに移動すると `(` が見えます。したがって...
「signal は int と... を渡す関数」
うーん、この同じルールを `fp` にも使えます。
fp とは?
fp も括弧内にあるので、続行すると `*` が見えます。
「fp は ... へのポインタ」
スパイラル時計回りに続行すると、`(` に到達します。
「fp は、int を渡して... を返す関数へのポインタ」
これで関数括弧の外を続行し、`void` が見えます。
「fp は、int を渡して何も返さない(void)関数へのポインタ」
fp の処理が終わったので、`signal` に追いつきましょう。これで...
「signal は int と、int を渡して何も返さない(void)関数へのポインタを渡す関数」
まだ括弧内にいるので、次に見た文字は `*` です。
「signal は int と、int を渡して何も返さない(void)関数へのポインタを渡す関数で、... へのポインタを返す」
括弧内の項目を解決したので、時計回りに続行すると、別の `(` が見えます。
「signal は int と、int を渡して何も返さない(void)関数へのポインタを渡す関数で、int を渡して... を返す関数へのポインタを返す」
最後に続行すると、残っているのは単語 `void` だけです。したがって、signal の最終的な完全な定義は次のようになります。
「signal は int と、int を渡して何も返さない(void)関数へのポインタを渡す関数で、int を渡して何も返さない(void)関数へのポインタを返す」
const および volatile にも同じルールが適用されます。
例えば:
const char *chptr;
さて、chptr とは?
「chptr は const char へのポインタ」
これはいかがですか:
char * const chptr;
さて、chptr とは?
「chptr は char への const ポインタ」
最後に:
volatile char * const chptr;
さて、chptr とは?
「chptr は volatile char への const ポインタ。」
K&R II の 122 ページにある例でこのルールを練習してください。
Copyright © 1993, 1994 David Anderson
この著者の名前とこの通知が保持されている限り、この記事は自由に配布できます。