7

gcc でもコンパイルできるようにコードを変換しようとしています (現在、MSVC でのみコンパイルされます)。

私が立ち往生しているコードは、フォーマット文字列とゼロ個以上の引数 ( const char *format, ...) を入力として受け入れる疑似フォーマット関数にあります。次に、いくつかの引数を消費するプレースホルダーのいくつかを処理し、残りを動的に生成された新しい va_list と共に渡します。vsprintf

これは、新しいを生成するための実際のコードですva_list:

char *new_args = (char *) malloc(sum);
char *n = new_args;

for(int i = 0; i < nArgs; i++)
{
    int j   = order[i];
    int len = _getlen(types[j]);

    memcpy(n, args + cumulOffsets[j], len);
    n += len;
}

vsprintf(buffer, sFormat.c_str(), new_args);

私の弁護では、私はこのコードを書きませんでしたし、書きませんでした。実際、これまでの人生で見た中で最もハックなものの 1 つだと思います。

ただし、この関数は非常に複雑で、非常に古く、非常に重要です。また、何年も変更されていないため (今を除いて)、最初から書き直したいと思っていますが、それにかかる時間とバグが発生することを正当化することはできません。

だから、私はGCCでこれと同じことをする方法が必要です..しかし、そうでva_listはないchar *ので、私は得ています:

エラー: ISO C++ は、配列型 '__va_list_tag [1]' へのキャストを禁止しています
4

3 に答える 3

4

私は少し迷っています。動的に生成された新しいva_listが必要なのはなぜですか? 古いものを再利用しないのはなぜですか?

vsnprintf ()は現在のva_listオブジェクトを使用していると思います (それを呼び出すことができれば)。したがって、自由にva_start()を実行し、 va_arg()を介して必要な引数を使用し、残りの引数を va_list を介してvsnprintf ( )に渡し、次にva_end()を呼び出します。

何か不足していますか?なぜディープコピー?

ディープ コピーが必要な場合は、va_start()を新しくして、必要な引数をva_arg()で削除し、結果のva_listオブジェクトをvsnprintf()に渡します。

( va_argを呼び出すたびにva_listオブジェクトが変更され、次の呼び出しで次の引数が返されます。)

または、 va_copy()を使用することもできます。(ただし、必ずそれに対応するva_end()を続けてください。)

補遺: これらの va_ マクロは C89 & C99 標準に基づいていることにも注意してください。GNU g++ はそれらをサポートします。Microsoft はやや限定的です。


TonyK のコメントのフォローアップ:

上で述べたことは、 va_listから最初の N 個のアイテムを引き出す場合に機能します。真ん中からアイテムを引っ張っている場合、それはより困難です。

va_listを構築する移植可能な方法はありません。

ただし、フォーマット文字列を分解し、それを使用してオブジェクト タイプ (double、float、int など) を判別し、それぞれを独自のフォーマット文字列 (元のフォーマット文字列のサブセクション) で個別に出力できます。複数のsnprintf()呼び出しにより、オーバーヘッドが発生します。ただし、このルーチンがあまり頻繁に呼び出されない場合は、実行可能です。

適切に作成されたva_listを使用して、元のフォーマット文字列のサブセクションを出力することもできます。つまり、最初のvsnprintf()呼び出しは要素 1..3、2 番目の要素は 5..7、3 番目の要素は 10..13 などを出力します ( vsnprintf()は必要以上にva_listの余分な要素を無視するため)。必要なのは、一連の対応する format-string-fragments と、各vsnprintf()呼び出しの必要に応じてva_arg()を使用してva_listから項目をポップすることだけです。)

于 2010-12-26T19:37:01.117 に答える
1

ここで何をしようとしているのかを理解するのに十分なコンテキストはありませんが、va_list を COPY する必要がある場合は、va_copygcc がサポートする C99 標準関数を使用できる可能性があります (ただし、MS がサポートしているかどうかはわかりません)。 .

于 2010-12-27T04:56:11.417 に答える
0

これを行う方法がありますが、きれいではありません。

union {
      char *pa;
      va_list al;
      } au;

....
au.pa = new_args;
vsprintf(buffer, sFormat.c_str(), au.al);

キャストの代わりに共用体を使用するのは見苦しいですが、va_list が配列型の場合はキャストできません。

于 2014-04-22T09:26:11.197 に答える