当va_list具有由局部变量设置的长度时,vsprintf_s()不起作用

时间:2012-04-16 20:11:42

标签: c visual-c++

我有一个正常工作的实用程序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()确实存在这样的根本区别?

另外我知道变量参数不是很安全,应该小心使用,但这种无害的东西肯定不应该设置警报声。

感谢您就此问题提出任何意见。

2 个答案:

答案 0 :(得分:1)

va_start的第二个参数需要是函数声明中...之前的最后一个参数。因此,在第一种情况下需要iArgCount,在第二种情况下需要strMessageFormat。在第二个参数中使用其他任何东西(例如局部变量)会给你未定义的行为 - 希望编译器会给你一个错误,但它可能只是默默地接受它并做一些随机的事情。

答案 1 :(得分:1)

va_list变量用于从它之前的参数派生...的起始地址。这是一项要求。 你不能使用本地,你可能想做

va_start(lstArgs, strMessageFormat);

代替。