UP | HOME

C语言变参的一个陷阱

在C语言编程中,经常使用变参处理一些字符串工作。先来看段代码。

char *string_vformat(const char *format, va_list argv) {
    char *str = 0;
    size_t str_len = vsnprintf(0, 0, format, argv);

    str = (char *)malloc(str_len + 1);

    vsprintf(str, format, argv);
    str[str_len] = 0;

    return str;
}

char *string_format(const char *format, ...) {
    char *str = 0;

    va_list args;
    va_start(args, format);

    str = string_vformat(format, args);

    va_end(args);
    return str;
}

上面这段字符串格式化代码,在大多数情况下,都可以工作的很好。但是在一些Unix操作系统中,这段代码会崩溃,原因是va_list失效了。

通过Google找到一段话:**you can even process a va_list only once on some platforms.**

正确的办法是当需要多次使用va_list对象时,应该使用va_copy拷贝多个副本来使用。下面给出改进后的代码。

char *string_vformat(const char *format, va_list argv) {
    char *str = 0;
    va_list args;
    size_t str_len;

    /* va_list only once on some platforms */
    va_copy(args, argv);
    str_len = vsnprintf(0, 0, format, args);

    str = (char *)malloc(str_len + 1);

    vsprintf(str, format, argv);
    str[str_len] = 0;

    return str;
}

虽然va_copy是C99的标准,但微软的VC并没有实现。最后给出一个跨平台方案吧。

#ifndef va_copy
# ifdef __va_copy
#  define va_copy(dest, src) __va_copy((dest), (src))
# else
#  define va_copy(dest, src) memcpy((&dest), (&src), sizeof(va_list))
# endif
#endif

Date: 2018-11-30 Fri 00:17

Author: shixiongfei

Created: 2020-09-05 Sat 14:39

Emacs 27.1 (Org mode 9.3)