1

va_arg を使用して、GUI ライブラリでジェネリック ファクトリ関数を作成しようとしています。同じ関数で va_arg を 2 回渡すと、2 つの異なる値ではなく同じ値が渡されます。

GUIObject* factory(enumGUIType type, GUIObject* parent, ...){
   va_list vl;
   va_start(vl, parent);
   ...
   label->SetPosition(va_arg(vl, int), va_arg(vl, int));
   va_end(vl);
   return finalObjectPointer;
}

factory(LABEL, theParent, 100,200); // Results in position 200:200

この予期しない動作の原因は何ですか?

4

3 に答える 3

6

コンパイラは、引数を順番に評価することを保証されていません。いくつかのローカル変数を追加し、2つの割り当てを順番に実行します。

この他のスタックオーバーフローの投稿を参照してください。

int v1 = va_arg(vl, int);
int v2 = va_arg(vl, int);

label->SetPosition(v1, v2);

観察しているものを取得するには、まったく同じ値を2回取得します。おそらく、評価状況の未定義の順序の上にコンパイラのバグを積み上げるか、環境内のva_argの特定のマクロ展開の面白い側面が必要です。

于 2009-12-28T01:39:01.873 に答える
6

va_argマクロです。そのマクロの背後に隠れているのは実装定義です。つまり、代わりに実行される操作に副作用がある可能性がva_argあります。このため、va_arg2つの隣接するシーケンスポイント間で複数回使用することはお勧めできません。これは潜在的に未定義の動作であり、何かが発生する可能性があることを意味します。これはまさにあなたの場合に起こることのように見えます。その結果、から2つの同じ値を取得すると、この「奇妙な」動作が発生しますva_arg

一部の実装で未定義の動作がない場合でも、関数呼び出しでの引数評価の順序は指定されていません。つまり、「シーケンシャルリーダー」を使用方法で使用しても、意図したとおりに機能することは保証されません(意図したとおり)。 。

于 2009-12-28T01:46:44.073 に答える
2

異なる引数の評価の間にシーケンスポイントがないため、引数の評価中に同じ値(vlまたはそれが参照するもの)を2回変更すると、動作が指定されなくなります。

va_argの内部状態を変更して、vlどの引数がすでに処理されているかを登録します。引数の評価中にこれを2回実行すると、何が発生するかが指定されません。コンパイラとそれが使用する最適化により、2つの同一のパラメータが渡されるようです。

于 2009-12-28T01:46:38.027 に答える