8

va_argsを使用して、C++ で可変引数を試しています。このアイデアは便利で、実際に params 機能を介して C# でよく使用したものです。私を苛立たせているのは、上記の va_args に関する次の抜粋です。

また、va_arg は、取得した引数が関数に渡された最後の引数であるかどうか (または、そのリストの末尾を過ぎた要素であるかどうか) を判断しないことに注意してください。

関数に渡される可変引数の数を関数自​​体からプログラムで決定する方法がないとは信じがたいです。次のようなことを実行したいと思います。

void fcn(int arg1 ...)
{
    va_list argList;
    va_start(argList, arg1);

    int numRemainingParams = //function that returns number of remaining parameters
    for (int i=0; i<numRemainingParams; ++i)
    {
        //do stuff with params
    }
    va_end(argList);
}

繰り返しますが、上記のドキュメントでは、取得した引数がリストの最後かどうかを va_arg が判断しないことを示唆しています。しかし、この情報は何らかの方法でアクセスできる必要があると思います。

これを達成する標準的な方法はありますか?

4

5 に答える 5

10

関数自体の中から関数に渡される変数引数の数をプログラムで決定する方法がないとは信じがたいです。

それにもかかわらず、それは本当です。C / C ++は引数リストの最後にマーカーを配置しないため、呼び出された関数は実際に受け取っている引数の数を認識していません。引数の終わりをマークする必要がある場合は、リストの最後に何らかのマーカーを配置して、自分でマークする必要があります。

呼び出された関数は、提供された引数のタイプやサイズも認識していません。そのためprintf、友人は、フォーマット文字列に補間する値の正確なデータ型を指定するように強制します。また、不正なフォーマット文字列を使用してprintfを呼び出すことにより、プログラムをクラッシュさせることができます。

パラメータの受け渡しは、C ++ / C標準ではなく、特定のプラットフォームのABIによって指定されることに注意してください。ただし、ABIでは、C ++/C標準を実装できるようにする必要があります。たとえば、ABIは効率を上げるためにレジスタにパラメータを渡したい場合がありますが、その場合、va_argsを簡単に実装できない場合があります。したがって、引数もスタック上でシャドウされる可能性があります。ただし、C ++ / C標準ではこの情報を利用可能にする必要がないため、引数リストの最後を示すようにスタックにマークが付けられることはほとんどありません。したがって、不要なオーバーヘッドが発生します。

于 2012-10-15T18:02:57.250 に答える
6

C および C++ で可変引数が機能する方法は比較的単純です。引数はスタックにプッシュされるだけで、どのような引数があるかをある程度把握するのは呼び出し先の責任です。引数の数を決定する方法を提供する標準には何もありません。その結果、引数の数は、いくつかのコンテキスト情報 (たとえば、フォーマット文字列で参照される要素の数) によって決定されます。

個々のコンパイラは要素の数を認識している場合がありますが、この値を取得するための標準インターフェイスはありません。

ただし、代わりにできることは、可変個引数テンプレートを使用することです。関数に渡される引数に関する非常に詳細な情報を決定できます。インターフェースは見た目が異なり、引数を何らかのデータ構造に導く必要があるかもしれませんが、可変引数を使用して渡すことができない型でも機能するという利点があります。

于 2012-10-15T18:04:51.820 に答える
3

いいえ、ありません。そのため、可変引数は安全ではありません。それらはCの一部であり、「便利な」可変個引数関数の型安全性を実現するための表現力に欠けています。Cには、型だけでなく値に非常に正確に依存する構造が含まれているという事実に従わなければなりません。それが「危険な言語」である理由です。

C++では可変引数を使用しないでください。これははるかに強力な言語であり、安全で同じように便利なコードを書くことができます。

于 2012-10-15T18:02:37.453 に答える
1

いいえ、そのような方法はありません。このような必要がある場合は、これらの関数パラメーターを、std::vector反復可能なまたは同様のコレクションにパックするのがおそらく最善です。

于 2012-10-15T18:03:24.890 に答える
1

可変引数リストは、C++ の C の歴史から継承された非常に古い概念です。それは、C プログラマーが通常、生成されたアセンブラー コードを念頭に置いていた時代にさかのぼります。

その時点で、コンパイラは、呼び出し時に関数に渡したデータが、関数が受け取ると予想されるデータ型と一致するかどうかをまったくチェックしませんでした。それを正しく行うのはプログラマーの責任でした。たとえば、呼び出し元が a を指定して関数を呼び出し、関数が acharを予期しintていた場合、コンパイラは文句を言いませんが、プログラムはクラッシュしました。

今日の型チェックはこれらのエラーを防ぎますが、可変引数リストを使用すると、すべてのリスクを含む古い概念に戻ります。したがって、回避できる場合は使用しないでください。

この概念が数十年前のものであるという事実は、おそらく、安全なコードの現代の概念と比較して間違っていると感じる理由です.

于 2012-10-15T18:38:31.207 に答える