C言語のエラー処理で思い悩む

C言語のエラー処理は戻り値で返すのが一般的ですよね。

errnoのようにスレッドローカル変数に格納して返すのも可能ですが、この時に戻り値をどうするかなどの問題もあり、やはり戻り値ベースが無難です。

エラー処理で重要なのはエラーを握りつぶさないことですが、実践的にはエラー判定時、即returnだけでなくgoto エラーラベルで異常系時の解放処理を分離するパターンもあります。

try-catch-finallyのfinallyに当たるものですね。

ここまで考えると、setjmpでtry-catch-finallyもどきを作るのもアリかなと思って、一発ネタ検討考えてみました。ネットを検索すると関数内でのジャンプが可能なものは多々あります。

以下がネタ。

typedef struct __try_location {
  struct __try_location *next;
  jmp_buf jmpbuf;
} __try_location;

{
	__try_location current;
	int __status_exception = setjmp(__init_try_location(&current));
	int __rethrow = 0;
	if(__status_exception == 0) {
		// try ブロック
	}
	if(__status_exception != 0) {
		// catchブロック
		__rethrow = 1;
	}
	for(; i++ <= 0; __rethrow != 0? rethrow_exception() ? 0) {
		// finallyブロック
	}
}

これなら、try-catch-finallyのマクロに置き換えられそう。catchだけはブロック中で例外タイプの判定が必要だけども。__init_try_locationはリスト要素として使用でき、スレッドローカル変数へチェインを登録します。__rethrow_exception()でさらなる__try_locationをjmp_bufの巻き戻し。

スレッドローカル変数アクセスとjmp_bufのレジスタコンテキスト保存にかかるオーバーヘッドが心配。(10個レジスタあると10x64bitの保存とかになるし・・・)

ちなみにWin32構造化例外は__exceptブロックに入ると変数がすべてレジスタからの再読み込みとなり、レジスタコンテキストを特別に保存はしていないようです。スタックフレームを巻き戻してexceptブロックを特定しているのではないかと思います。