おことわり: この記事では「1975年頃のC言語」仕様を解説します。2017年現在のC言語仕様とは異なるため、あなたのC言語ライフには役立たないことを予めご承知おきください。
(本投稿は Ancient C探訪記 シリーズの一部です。)
続いては「ラベル(Label)」を見ていきます。goto文と組み合わせるアレです。アレ。
Ancient Cのラベル
"C Reference Manual" §9.11 Goto statement, §14.4 Labels からそれぞれ引用します。Ancient Cのgoto文には、ラベル(label)名 または ラベルに評価されるint
型へのポインタ を指定します。
Control may be transferred unconditionally by means of the statement
goto expression ;
The expression should be a label (§9.12, 14.4) or an expression of type "pointer to
int
" which evaluates to a label. It is illegal to transfer to a label not located in the current function unless some extra language provision has been made to adjust the stack correctly.
Ancient Cでは、「ラベルそれ自身は型(type)を持たないがint
の配列型とみなす」「ラベル変数はint
へのポインタ型として宣言する」という仕様になっています。なんという日和見主義。
Labels do not have a type of their own; they are treated as having type "array of
int
". Label variables should be declared "pointer toint
"; before execution of agoto
referring to the variable, a label (or an expression deriving from a label) should be assigned to the variable.
int *target; /* ラベル変数を宣言(intへのポインタ型) */
target = label; /* ラベル名をラベル変数へ代入 */
goto target; /* ラベル変数が指す先のラベルにジャンプ */
label:
/* 処理 */
標準規格との差分
標準規格ではgoto文にラベル名のみを指定でき、このような「ラベル変数」はサポートされません。同機能が無いことで困る人はあまり居ないかもしれませんが、ラベル変数を用いた computed goto というテクニックは、プログラミング言語の処理系(インタプリタや仮想マシン)実装では高速化に大きく貢献するそうです。
なお標準Cではありませんが、GCC CコンパイラのGNU拡張では少し違う構文でラベル変数を実現しています。
void *target; /* ラベル変数を宣言(voidへのポインタ型) */
target = &&label; /* &&演算子によりラベルを値として扱う */
goto *target; /* ラベル変数が指す先のラベルにジャンプ */
適当に明日以降につづきます。