28

ゼロから作成する方法はありva_listますか?パラメータとしてをとる関数を呼び出そうとしてva_listいます:

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

...可変数の引数をとらない関数から。私が考えることができる唯一の方法は、varargsを受け取り、その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の署名を変更できません。

4

4 に答える 4

14

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

バグを期待する

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

また、man(3)va_copyとその仲間をチェックアウトして、va_argsをより安全に処理し、それらを渡します。

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

于 2009-06-12T18:42:47.540 に答える
6

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

于 2009-06-12T19:29:39.940 に答える
5

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

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

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

于 2009-06-12T22:17:43.577 に答える
5

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

glibライブラリはこれらのラッパーを広範囲に使用します。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)
}
于 2016-12-29T09:50:37.647 に答える