0

正しく機能するユーティリティC関数があります。

void UtilDisplayMessage(char* strCaption, char* strMessageFormat, int iArgCount, ...)
{
    // Initialize the variable arg list
    va_list lstArgs;
    va_start(lstArgs, iArgCount);

    // Format the message
    vsprintf_s(g_strMessage, UTIL_DEF_MESSAGE_SIZE, strMessageFormat, lstArgs);

    // Destroy the variable arg list
    va_end(lstArgs);

    // Use formatted string here...
}

しかし、「iArgCount」パラメーターを削除したいので、次のようなテスト関数を作成しました。

void UtilDisplayMessageEasy(char* strCaption, char* strMessageFormat, ...)
{
    // Initialize the variable arg list
    va_list lstArgs;

    int iParamCount = 1;
    va_start(lstArgs, iParamCount);

    // Format the message
    vsprintf_s(g_strMessage, UTIL_DEF_MESSAGE_SIZE, strMessageFormat, lstArgs);

    // Destroy the variable arg list
    va_end(lstArgs);

    // Use formatted string here...
}

しかし、この呼び出しで整数値を渡すと、偽の結果が得られます。

UtilDisplayMessageEasy("TEST", "The value is %i.", 1);

そして、この呼び出しで文字列を渡すと、アクセス違反の例外が発生します。

UtilDisplayMessageEasy("TEST", "This is only a %s.", "TEST");

それでも、元の関数を次のように呼び出すと、正常に機能します。

UtilDisplayMessage("TEST", "This is only a %s.", 1, "TEST");

引数パラメーターとローカルパラメーターのどちらをva_start()に渡すかについて、本当にそのような根本的な違いはありますか?

また、変数パラメータはあまり安全ではなく、注意して使用する必要があることも承知していますが、この無害なものでアラームが鳴るようなことはありません。

この問題に関してご意見をお寄せいただきありがとうございます。

4

2 に答える 2

1

の2番目の引数は、関数宣言のva_start前のLASTPARAMETERである必要があります。したがって、最初のケースと2番目のケースである...必要があります。2番目の引数(ローカル変数など)で他のものを使用すると、未定義の動作が発生します。コンパイラーがエラーを表示することを願っていますが、それを黙って受け入れてランダムに実行する可能性があります。iArgCountstrMessageFormat

于 2012-04-16T20:39:33.557 に答える
1

va_list変数は、直前の引数から...の開始アドレスを導出するために使用されます。それは要件です。あなたはローカルを使用することはできません、あなたはしたいかもしれません

va_start(lstArgs, strMessageFormat);

代わりは。

于 2012-04-16T21:00:52.627 に答える