2009-02-25 2 views
46

va_end - マクロをリセットするarg_ptr正確にva_endとは何ですか?それはいつもそれを呼び出す必要がありますか?

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

+1

本当に良い質問です。私は誰かがva_endがノーオペレーションではないアーキテクチャを記述することでそれに答えることを望みます。 – erikkallen

+1

FYI:MSVS2008 - #define _crt_va_end(ap =(va_list)0) – Yarik

+0

@erikkallen: "va_endを定義する"ためのgoogle検索を実行すると、本質的に無意味な定義である場合とそうでない場合がある、 op。 – PlasmaHH

答えて

40

va_endを使用してクリーンアップします。あなたはスタックを粉砕したくないのですか? man va_startから

はva_end()

のva_startの各呼び出しは()と同じ関数ではva_endの対応する呼び出し()にマッチしなければなりません。 va_end(ap)の呼び出しの後、変数apは未定義です。 va_start()とva_end()で囲まれたリストの複数のトラバーサルが可能です。 va_end()はマクロまたは関数である可能性があります。

注単語必見の存在。

va_start()が実行していることがわからないので、スタックが破損する可能性がありますva_*マクロはブラックボックスとして扱われます。すべてのプラットフォーム上のすべてのコンパイラは、それが望むものを何でもできる。それは何もしないかもしれない、またはそれはたくさんするかもしれません。

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

+0

ポインタが 'グローバル'であることを意味します。ポインタをリセットせずに関数を2回目に呼び出すと、スタックが壊れますか? – Yarik

+3

va_start()が何をしているのかわからないので、破損する可能性があります。そしてそれはきれいにする必要があります。したがって、va_start()を呼び出すと、va_end()と一致する必要があります。 – greyfade

+0

説明をありがとうございます。 – Yarik

10

一般的な "パラメータはスタックに渡されました"実装では、va_end()は通常は空/空ではないと考えられます。しかし、伝統的なスキームが少ないプラットフォームでは、それが必要になります。プラットフォームの中立性を維持するためにそれを含めることは「良い習慣」です。 Linuxの

+0

すべてのvar_argsに対して繰り返し処理を行わなかった場合は、スタックをリセットすることができます。 – Spidey

11

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

va_copyの()

明らかva_listの実装は、variadicな関数の スタックフレームへのポインタでなければなりません。こうした設定では(はるかに多い )があり、それ (長さ1の)ポインタの配列にするシステムもあり、そこに一つは

を必要とし、

va_list aq = ap; 

残念なことに割り当てに対して何も存在しないようです

va_list aq; 
    *aq = *ap; 

最後に、引数がレジスタに渡されるシステムでは、それは(そののva_argよう、またのva_start()、 を、メモリを割り当てるが、引数を格納する引数が次であるかの指示のために必要 であってもよいです)できます ステップリストを介して。今すぐva_end()は割り当てられたメモリ を解放することができます。このような状況に対応するために、C99)は、(はva_endの対応invoca- ンにマッチしなければならない)、上記割り当ては

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

va_copyの各呼び出し(置き換えを行うことができるマクロva_copyの()、そう を追加します同じ機能で va_copy()を提供していないシステムでは、代わりに__va_copyが使用されています。これは、 ドラフト提案で使用されている名前であるためです。

+2

これをcliarfyするには。 Linux x86-64では特別なことはありません。あなたが 'va_list'変数だけを利用可能にしているときにリストを2回反復したい場合、' va_copy'が必要です。 (例えば、引数として 'va_list'を取る関数の中で)。あなたはいつでも 'va_start'と' va_end'をいつでも呼び出すことができます。 –

+0

@MattMcNabb on x86-64 'va_list'はトラバーサル状態を維持します。 x86ではそうではありません。 –

+0

@downvoter何が間違っていますか? –

関連する問題