22

setjmp() の呼び出し以降に値が変更された可能性がある場合、longjmp() の呼び出し後、非 volatile 修飾ローカル オブジェクトにアクセスしないでください。この場合の値は不確定と見なされ、それらへのアクセスは未定義の動作です。

今私の質問は、なぜ揮発性がこの状況で機能するのですか? その volatile 変数を変更しても longjmp は失敗しませんか? たとえば、次の例で longjmp はどのくらい正しく機能しますか? コードが longjmp の後で setjmp に戻った場合、local_var の値は 1 ではなく 2 になりませんか?

void some_function()
{
  volatile int local_var = 1;

  setjmp( buf );
  local_var = 2;
  longjmp( buf, 1 );
}
4

3 に答える 3

23

setjmpそしてlongjmpクロバーレジスタ。変数がレジスタに格納されている場合、その値はlongjmp.

逆に、 として宣言されている場合volatileは、書き込まれるたびにメモリに格納され、読み取られるたびにメモリから読み取られます。これは、コンパイラがレジスタを使用する代わりに、より多くのメモリ アクセスを実行する必要があるため、パフォーマンスが低下しますが、変数の使用はlongjmping に直面しても安全になります。

于 2011-11-03T14:52:53.693 に答える
12

このシナリオで重要なのは最適化です。オプティマイザーは当然、setjmp() のような関数の呼び出しがローカル変数を変更しないことを期待し、変数への読み取りアクセスを最適化して取り除きます。例:

int foo;
foo = 5;
if ( setjmp(buf) != 2 ) {
   if ( foo != 5 ) { optimize_me(); longjmp(buf, 2); }
   foo = 6;
   longjmp( buf, 1 );
   return 1;
}
return 0;

foo は 2 行目に書き込まれており、4 行目で読み取る必要はなく、5 行目であると見なすことができるため、オプティマイザーは optimize_me 行を最適化して取り除くことができます。 longjmp が通常の C 関数の場合も同様です。ただし、setjmp() と longjmp() は、オプティマイザが説明できない方法でコード フローを妨害し、このスキームを壊します。このコードの正しい結果は終了です。ラインを最適化すると、無限ループになります。

于 2011-11-03T14:51:18.853 に答える
8

「揮発性」修飾子がない場合の問題の最も一般的な理由は、コンパイラがローカル変数をレジスタに配置することが多いためです。これらのレジスタは、ほぼ確実に setjmp と longjmp の間の他の目的で使用されます。これらのレジスターを他の目的で使用することによって、longjmp の後で変数が誤った値を保持しないようにする最も実用的な方法は、これらのレジスターの値を jmp_buf にキャッシュすることです。これは機能しますが、コンパイラーが jmp_buf の内容を更新して、レジスターがキャッシュされた後に変数に加えられた変更を反映する方法がないという副作用があります。

それが唯一の問題である場合、volatile と宣言されていないローカル変数にアクセスした結果は不確定になりますが、未定義の動作にはなりません。ただし、メモリ変数にも問題があります。これは、thiton が暗示しています。たとえローカル変数がたまたまスタックに割り当てられていたとしても、コンパイラは、その値がもはや存在しないと判断したときはいつでも、その変数を別のもので自由に上書きできます。必要です。たとえば、コンパイラは、ルーチンが他のルーチンを呼び出したときに一部の変数が「ライブ」にならないことを識別し、それらの変数をスタック フレームの最も浅い位置に配置して、他のルーチンを呼び出す前にポップすることができます。このようなシナリオでは、setjmp() が呼び出されたときに変数がメモリ内に存在していたとしても、そのメモリはリターン アドレスを保持するなどの別の用途に再利用されている可能性があります。そのため、longjmp() が実行された後、

'volatile' 修飾子を変数の定義に追加すると、その変数がスコープ内にある限り、その変数を使用するためだけにストレージが予約されます。setjmp と longjmp の間で何が起こっても、コントロールが変数が宣言されたスコープを離れていなければ、その場所を他の目的に使用することはできません。

于 2011-11-03T15:01:12.927 に答える