我经常希望有一种简单的方法来使用 sprintf/snprintf 构造字符串,而无需定义本地数组的麻烦,如下所示:
char str[256];
snprintf(str, sizeof(str), format, ...);
use_string(str);
我突然想到我可以使用复合文字来做到这一点:
static inline char* snprintf_assert(char* str, int max_size, const char* format, ...) {
va_list arg;
va_start(arg, format);
int count = vsnprintf(str, max_size, format, arg);
va_end(arg);
assert(count >= 0 && count < max_size);
return str;
}
// Helper sprintf that allocates a buffer local to the block.
// It's using the fact that (char[N]){} will allocate a l-value
// with lifetime tied to the local block.
#define local_sprintf(N, ...) snprintf_assert((char[N]){}, N, __VA_ARGS__)
用途:
use_string(local_sprintf(256, format, ...));
我相信这是明确定义的,因为复合文字数组的生命周期将与封闭块相关联。有什么理由可以避免这种情况吗?
与在调用
snprintf_assert
之前简单定义本地数组相比,此技术存在一些缺点:
定义固定大小的数组
N
可移植到不支持 VLA 和复合文字的 C++ 和 C 实现。
复合文字
(char[N]){}
(您可以编写 (char[N]){0}
以便向后移植到 C99)定义但也初始化临时未命名数组,因此您会产生额外的 memset()
N
字节到 0
。这可能不是一个很大的开销,除非您使 N
变大以容纳潜在的大型构造字符串。