web-dev-qa-db-ja.com

va_listへの入力

va_listを最初から作成する方法はありますか? va_listをパラメーターとして受け取る関数を呼び出そうとしています。

func(void **entry, int num_args, va_list args, char *key); 

...可変数の引数をとらない関数から。私が考えることができる唯一の方法は、可変引数を取り、そのva_listを渡す中間関数を作成することです。これはかなりばかげています。

void stupid_func(void **entry, char *key, int num_args, ...) {
    va_list args;
    va_start(args, num_args);

    func(entry, num_args, args, key);

    va_end(args);
}

もっと良い方法はありますか? funcの署名を変更できません。

25
kristina

これは悪い考えです。va_listの抽象化がいくつかのgrimスタックポインタなどに関するコンパイラ/アーキテクチャ固有の詳細。また、初期化されると、関数のスコープにほぼバインドされます。スタックを巻き上げて前のフレームva_argsをスコープ外で参照すると、状況が悪化する可能性があります。あなたはそれらを回すことができますが...

バグが予想されます

参照: http://lists.freebsd.org/pipermail/freebsd-AMD64/2004-August/001946.html

また、man(3)va_copyとその友達をチェックアウトして、va_argsのより安全な処理とそれらの受け渡しを確認してください。

私見では、va_argsのものはあまりきれいではありません。過去に、ヒープ上の構造体/不透明なポインターを初期化し、ポインター演算を使用してデータを処理することでこれに対処しました。しかし、これはハックであり、状況によって異なります。

14
Aiden Bell

私はエイデンの警告を理解し、同意します-va_listや友人は、低レベルの呼び出し規約を隠しているため危険です。しかし...この状況では、他に選択肢はないと思います。置く static ...関数を.cファイルを作成して、他の誰もそれを見ることができないようにします。呼び出す必要のある関数のプロキシのようなもので、それをテストして完了します。コールチェーンの上流で可変個引数の引数を公開しないように注意してください。

6

_va_list_を作成するプロキシ関数のアイデアはそれを行う正しい方法です。そのプロキシがパブリックスコープを持つ必要はありません。ただし、プロキシがすでに存在している場合があります。たとえば、多くのライブラリ実装では、sprintf()vsprintf()の単なるプロキシです。

コードを特定のコンパイラとターゲットプラットフォームに結び付けようとしない限り、これ以上の方法はありません。 _<stdarg.h>_で定義されている名前は、可変引数リストへのアクセスをサポートするためのポータブルで一貫性のあるインターフェイスを提供するためにあります。可変個引数関数を実装および使用するための唯一の移植可能な方法は、そのインターフェースを使用することです。

とはいえ、配列内の呼び出しフレームを複製し、それを正しく参照する_va_list_を手動で作成することで、移植性を犠牲にする可能性があります。結果は決して移植可能ではありません。

5
RBerteig

君の stupid_funcは完全に有効なCコードです。そうでない場合、vprintfや同様の関数をどのように呼び出すと思いますか?

glib library これらのラッパーを広範囲に使用します。 C99仕様自体は、例に似たものがあります。セクションからの抜粋7.19.6.8

以下に、一般的なエラー報告ルーチンでのvfprintf関数の使用法を示します。

#include <stdarg.h>
#include <stdio.h>
void error(char *function_name, char *format, ...)
{
    va_list args;
    va_start(args, format);
    // print out name of function causing error
    fprintf(stderr, "ERROR in %s: ", function_name);
    // print out remainder of message
    vfprintf(stderr, format, args);
    va_end(args)
}
4
ntd