在C语言编程中,经常使用变参处理一些字符串工作。先来看段代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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拷贝多个副本来使用。下面给出改进后的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| char *string_vformat(const char *format, va_list argv) { char *str = 0; va_list args; size_t str_len;
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并没有实现。最后给出一个跨平台方案吧。
1 2 3 4 5 6 7
| #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
|