C++变量参数错误

Tom*_*Tom -2 c c++ variadic-functions

我最近在MSVC(2013)中偶然发现了一个奇怪的行为,我想澄清有关变量参数的问题.

在"..."之前看起来有多个参数会导致意外行为

int formatString(const char* msg, char* buffer, int bufferLength, ...)
{
    int length = 0;
    if (msg != nullptr) {
        va_list args;
        va_start(args, msg);
        length = vsnprintf_s(buffer, bufferLength, bufferLength, msg, args);
        va_end(args);
    }

    return length;
}
Run Code Online (Sandbox Code Playgroud)

像这样调用这个函数

const char* message = "A word: %s and a number %d";
const int bufferLength = 1024;
char buffer[bufferLength];
int formattedMsgLen = formatString(message, buffer, bufferLength, "cheese", 4);
Run Code Online (Sandbox Code Playgroud)

会立即导致程序崩溃.如果我之前将缓冲区设置为0

memset(buffer, 0, 1024); // We know sizeof(char) == 1
Run Code Online (Sandbox Code Playgroud)

这被写入缓冲区:

"A word: A word:  and a number 1024". 
Run Code Online (Sandbox Code Playgroud)

这是完全错误的......

但是,如果我将函数更改为采用结合了前三个参数的结构

struct Message
{
    const char* msg;
    char* buffer;
    int bufferLength;
};

int formatString(Message msg, ...)
{
    int length = 0;
    if (msg.msg != nullptr) {
        va_list args;
        va_start(args, msg);
        length = vsnprintf_s(msg.buffer, msg.bufferLength, msg.bufferLength, msg.msg, args);
        va_end(args);
    }

    return length;
}
Run Code Online (Sandbox Code Playgroud)

调用新函数时如下:

const int bufferLength = 1024;
char buffer[bufferLength];
Message msg;
msg.buffer = buffer;
msg.msg = "A word: %s and a number %d";
msg.bufferLength = bufferLength;
int formattedMsgLen = formatString(msg, "cheese", 4);
Run Code Online (Sandbox Code Playgroud)

这被写入缓冲区:

"A word: cheese and a number 4"
Run Code Online (Sandbox Code Playgroud)

这是正确的,这是我所期望的.我是否认为你以前只能使用只有一个参数的函数的vaargs?我不认为是这种情况,因为下面的函数有多个第一个参数

int fprintf(FILE *, const char *fmt, ...);
int sprintf(char *s, const char *fmt, ...);
Run Code Online (Sandbox Code Playgroud)

这可能是编译器中的错误吗?不太可能....

它可能不是,我做了一些愚蠢的事情,但我对发生的事情感到困惑.如果有人能对此有所了解,我将非常感激.

谢谢!

Mar*_*n R 8

va_start()必须使用变量参数列表前的最后一个参数的名称调用:

int formatString(const char* msg, char* buffer, int bufferLength, ...)
{
    // ...

    va_list args;
    // va_start(args, msg);   <-- WRONG!
    va_start(args, bufferLength); 

    // ...
}
Run Code Online (Sandbox Code Playgroud)