65

va_end- リセットするマクロarg_ptr

可変引数リストにアクセスした後、arg_ptrポインタは通常 でリセットされva_end()ます。リストを繰り返したい場合は必要なのは理解していますが、そうしない場合は本当に必要ですか? default:「常にあなたの」というルールのように、それは単なる良い習慣switchですか?

4

3 に答える 3

55

va_endクリーンアップを行うために使用されます。スタックを壊したくありませんよね?

からman va_start:

va_end()

va_start() の各呼び出しは、同じ関数内の対応する va_end() の呼び出しと一致する必要があります。va_end(ap) の呼び出し後、変数 ap は未定義です。それぞれが va_start() と va_end() で囲まれた、リストの複数の走査が可能です。va_end() は、マクロまたは関数の場合があります。

mustという単語が存在することに注意してください。

何をしているのかわからないva_start()ため、スタックが破損する可能性があります。マクロは、va_*ブラック ボックスとして扱われることを意図しています。すべてのプラットフォームのすべてのコンパイラは、そこでやりたいことを何でもできます。何もしない場合もあれば、多くのことを行う場合もあります。

一部の ABI は、最初のいくつかの引数をレジスタに渡し、残りをスタックに渡します。Ava_arg()もっと複雑な場合があります。特定の実装が varargs をどのように処理するかを調べることができますが、これは興味深いかもしれませんが、移植可能なコードを作成する際には、それらを不透明な操作として扱う必要があります。

于 2009-02-25T18:03:54.060 に答える
15

va_listLinux x86-64 では、変数に対して実行できるトラバーサルは 1 つだけです。va_copyより多くのトラバーサルを行うには、 firstを使用してコピーする必要があります。man va_copy詳細を説明します:

va_copy()

明らかな実装では、va_list が可変個引数関数のスタック フレームへのポインターになります。このような設定 (最も一般的な設定) では、割り当てに反対するものは何もないようです。

   va_list aq = ap;

残念ながら、それを (長さ 1 の) ポインターの配列にするシステムもあり、その必要があります。

   va_list aq;
   *aq = *ap;

最後に、引数がレジスタで渡されるシステムでは、va_start() がメモリを割り当て、そこに引数を格納し、次の引数を示すために、va_arg() がリストをステップ実行できるようにする必要がある場合があります。これで va_end() は割り当てられたメモリを再び解放できるようになりました。この状況に対応するために、C99 はマクロ va_copy() を追加して、上記の割り当てを次のように置き換えることができます。

   va_list aq;
   va_copy(aq, ap);
   ...
   va_end(aq);

va_copy() の各呼び出しは、同じ関数内の対応する va_end() の呼び出しと一致する必要があります。va_copy() を提供しない一部のシステムでは、代わりに __va_copy があります。これは草案で使用された名前だからです。

于 2012-04-03T21:00:46.780 に答える
13

一般的な「スタックで渡されるパラメーター」の実装では、va_end() は通常、何もない/空/null であると思います。ただし、従来のスキームが少ないプラットフォームでは、必要になります。プラットフォームの中立性を保つためにこれを含めることは「良い習慣」です。

于 2009-02-25T18:08:52.223 に答える