ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
Oracle Solaris Studio 12.3: C ユーザーガイド Oracle Solaris Studio 12.3 Information Library (日本語) |
2.11.3 does_not_read_global_data
2.11.5 does_not_write_global_data
2.11.26 warn_missing_parameter_info
2.14.5 __FUNCTION__ と __PRETTY_FUNCTION__
2.16.1 -I- オプションによる検索アルゴリズムの変更
2.18 Intel MMX および拡張 x86 プラットフォーム組み込み関数のためのコンパイラサポート
C コンパイラは、計算型 goto 文として知られる C の拡張機能を認識します。計算型 goto 文を使用すると、実行時に分岐先を判別することができます。次のように演算子 '&&' を使用して、ラベルのアドレスを取得し、void * 型のポインタに割り当てることができます。
void *ptr; ... ptr = &&label1;
あとに続く goto 文は、ptr により label1 に分岐できます。
goto *ptr;
ptr は実行時に計算されるため、ptr は有効範囲内にある任意のラベルのアドレスを取得でき、goto 文はこのアドレスに分岐することができます。
ジャンプテーブルを実装するには、計算型 goto 文を次の方法で使用します。
static void *ptrarray[] = { &&label1, &&label2, &&label3 };
これで、次のようにインデックスを指定して配列要素を選択できます。
goto *ptrarray[i];
ラベルのアドレスは、現在の関数スコープからのみ計算できます。現在の関数以外のラベルについてアドレスを取得しようとすると、予測できない結果になります。
ジャンプテーブルは switch 文と同様の働きをしますが、ジャンプテーブルではプログラムフローの追跡がより困難になる可能性があります。顕著な相違点は、switch 文のジャンプ先はすべて、予約語 switch から見て順方向になることです。計算型 goto を使用してジャンプテーブルを実装すれば、順方向、逆方向のどちらにも分岐させることができます。
#include <stdio.h> void foo() { void *ptr; ptr = &&label1; goto *ptr; printf("Failed!\n"); return; label1: printf("Passed!\n"); return; } int main(void) { void *ptr; ptr = &&label1; goto *ptr; printf("Failed!\n"); return 0; label1: foo(); return 0; }
次の例では、プログラムフローの制御にジャンプテーブルを使用しています。
#include <stdio.h> int main(void) { int i = 0; static void * ptr[3]={&&label1, &&label2, &&label3}; goto *ptr[i]; label1: printf("label1\n"); return 0; label2: printf("label2\n"); return 0; label3: printf("label3\n"); return 0; } %example: a.out %example: label1
計算型 goto の別の利用は、スレッド化されたコードのインタプリタとしてです。高速ディスパッチを行うために、インタプリタ関数の範囲内にあるラベルアドレスを、スレッド化されたコードに格納することができます。