setjmp マクロは C の標準ライブラリの一部ですが、知らない方も少なくないでしょうし、知っていても使ったことがない方も多いでしょうから、今回は本題に入る前に、少し setjmp の解説から行うことにします。
setjmp というのは、<setjmp.h> ヘッダで定義されるマクロで、同じヘッダで宣言される longjmp と組み合わせて使用します。C++ の例外と同じように、関数の枠組みを飛び越えて、呼び出し元の関数の特定の場所へジャンプすることができます。
#include <setjmp.h>
jmp_buf env;
void f(void)
{
longjmp(env, 1);
}
void g(void)
{
if (setjmp(env) == 0)
{
/* 最初はこちらのブロックが実行される */
f();
}
else
{
/* f 関数内の longjmp が実行されると、こちらのブロックが実行される */
}
}
setjmp マクロを実行すると、その時点での情報を jmp_buf 型の引数(上記の例では env)に保存します。そして、setjmp マクロは必ず 0 を返します。
その後、longjmp 関数が setjmp マクロで状態を保存した jmp_buf 型の引数を伴って呼び出されると、setjmp を呼び出した場所に制御が移ります。そして、longjmp に第 2 引数として与えた値を返却値として、あたかも setjmp マクロの実行を終えたかのように振舞います。
setjmp と longjmp の組み合わせを使って、ちょっと凝ったことをしようと思うと、setjmp マクロの返却値をいったん変数に代入(あるいは初期化)したいと考えるのは当然のことです。
int cause = setjmp(env);
のようにです。しかし、上記のような使い方は C の規格上許されません。この制約を課す記述を JIS X3010:2003 から引用すると、
環境限界
setjmpマクロの呼出しは,次に示すいずれかの文脈にしか現れてはならない。
- 選択文又は繰返し文の制御式全体
- 他方のオペランドが整数定数式である関係演算子又は等価演算子の一方のオペランド。この場合,関係演算し又は等価演算しによる式は,選択文又は繰返し文の制御式全体でなければならない。
- 単項 ! 演算子のオペランド。この場合,単項 ! 演算子による式は,選択文又は繰返し文の制御式全体でなければならない。
- 式文の式全体(
voidにキャストされていてもよい。)。
setjmpマクロの呼出しがこれ以外の文脈に現れた場合,その動作は,未定義とする。
すなわち、宣言の中に現れる(他の変数を初期化する)ことも、代入演算子のオペランドになる(他の変数に代入する)ことも、未定義の動作を引き起こすことになるわけです。
したがって、setjmp マクロの返却値によって処理を振り分ける唯一の方法は switch 文ということになります。どうしても変数に代入したい場合は、jmp_buf 型の変数とあわせて別の変数をもう一つ管理し、その変数を setjmp の返却値の代わりに使う必要があります。
トラックバック
ブックナビゲーション
- 技術情報
- Boost C++ Libraries メモ
- C++と組込み環境
- C++サンプル集
- C++テンプレート集
- C++プログラマのためのC言語入門
- C/C++迷信集
- [迷信] 'A'~'Z' の値は連続している
- [迷信] 0xe-0xe はゼロ
- [迷信] 1 バイトは 8 ビット
- [迷信] 2の累乗による割り算と右シフトは等価
- [迷信] FILE 型は構造体
- [迷信] abs は常に非負の値を返す
- [迷信] argv[0] はプログラム名
- [迷信] char 型は符号付き
- [迷信] double の出力書式は "%lf"
- [迷信] fflush で入力バッファをクリア
- [迷信] free でメモリを開放する
- [迷信] free に NULL を渡すとクラッシュする
- [迷信] gets は単純に fgets に置き換えられる
- [迷信] isalpha 関数の引数は char 型
- [迷信] new に失敗すると NULL が返る。
- [迷信] scanf ではバッファオーバーランを防げない
- [迷信] scanf でキーボードから入力
- [迷信] setjmp マクロの返却値は変数に代入できる
- [迷信] sizeof は定数式
- [迷信] void main(void)
- [迷信] とりあえず memset で初期化
- [迷信] アルゴリズム関数内で関数オブジェクトはコピーされない
- [迷信] オブジェクトの動的生成に失敗するとメモリリークする
- [迷信] コンストラクタから例外を送出してはならない
- [迷信] コンストラクタで自身をゼロクリア
- [迷信] コンパイラはプログラマの心を察してくれる
- [迷信] コンパイルエラーが出るのでアクセス指定子を修正
- [迷信] ソースコード中の即値を全廃せよ
- [迷信] ソースファイルの末尾に }
- [迷信] データ列のソートには qsort 関数を使うべし
- [迷信] プログラムは必ず main から始まる
- [迷信] 一重引用符の中には一文字しか書けない
- [迷信] 今どき int が 16 ビットの処理系なんて無い
- [迷信] 入力データ格納用配列のサイズは BUFSIZ
- [迷信] 割付けたメモリはプログラマが自分で解放しなければならない
- [迷信] 実数型とは浮動小数点型のことである
- [迷信] 引用符で囲んだヘッダ名はカレントディレクトリから探索する
- [迷信] 文字列から整数への変換には atoi
- [迷信] 構造体のタグ名は下線で始める
- [迷信] 構造体はクラスではない
- [迷信] 識別子に使える文字は英数字と下線のみ
- [迷信] 非局所オブジェクトは外部結合
- C言語再入門
- C言語徹底入門
- Drupal メモ
- TOPPERS 情報
- ライブラリ開発入門
- 分割コンパイルをきわめる
- 擬似プロセッサを作る
- 車輪の再発明
- 過去の情報

