这个呢?
char *join_int_list(const unsigned int *list, size_t n_items)
{
enum { SIZEOF_INT_AS_STR = sizeof("4294967295,")-1 };
char *space = malloc(SIZEOF_INT_AS_STR * n_items);
if (space != 0)
{
size_t i;
char *pad = "";
char *dst = space;
char *end = space + SIZEOF_INT_AS_STR * n_items;
for (i = 0; i < n_items; i++)
{
snprintf(dst, end - dst, "%s%u", pad, list[i]);
pad = ",";
dst += strlen(dst);
}
space = realloc(space, dst - space + 1);
}
return(space);
}
调用者有责任释放返回的指针 - 并在使用它之前检查它是否不为空。如果分配的数量太大而无法使用,则“realloc()”会释放额外的空间。这段代码愉快地假设这些值确实是 32 位无符号整数;如果它们可以更大,那么枚举需要适当的调整。
测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *join_int_list(const unsigned int *list, size_t n_items)
{
enum { SIZEOF_INT_AS_STR = sizeof("4294967295,")-1 };
char *space = malloc(SIZEOF_INT_AS_STR * n_items);
if (space != 0)
{
size_t i;
char *pad = "";
char *dst = space;
char *end = space + SIZEOF_INT_AS_STR * n_items;
for (i = 0; i < n_items; i++)
{
snprintf(dst, end - dst, "%s%u", pad, list[i]);
pad = ",";
dst += strlen(dst);
}
space = realloc(space, dst - space + 1);
}
return(space);
}
int main(void)
{
static unsigned int array[]= { 1, 2, 3, 49, 4294967295U, 0, 332233 };
char *str = join_int_list(array, sizeof(array)/sizeof(array[0]));
printf("join: %s\n", str);
free(str);
return(0);
}
用 valgrind 检查 - 似乎没问题。
讨论INT_MAX或UINT_MAX转字符串:
您可以使用 sizeof("," STRINGIZE(INT_MAX)) 代替硬编码。 stringize 宏是一个常用的 cpp 工具,可以定义为 #define STRINGIZE_(v) #v 和 #define STRINGIZE(v) STRINGIZE_(v)。 – R.佩特
@R Pate:好主意 - 是的,你可以非常有效地做到这一点。实际上,其中有两个有趣的想法:使用带有 sizeof() 的字符串连接(为了清楚起见需要括号 - 但字符串连接发生得足够早,编译器不会担心)以及在 INT_MAX 上使用字符串化操作. ——乔纳森·莱弗勒
对INT_MAX 使用字符串化操作不是一个好主意——它必须是一个“常量表达式”,而不一定是数字序列。它可以定义为 ((1
@caf 是对的。考虑这段代码:
#include <limits.h>
#include <stdio.h>
#undef INT_MAX
#define INT_MAX (INT_MIN-1 - 100 + 100)
#define QUOTER(x) #x
#define STRINGIZER(x) QUOTER(x)
enum { SIZEOF_INT_AS_STR = sizeof("4294967295,")-1 };
enum { SIZEOF_INT_AS_STR_1 = sizeof(STRINGIZER(INT_MAX) ",")-1 };
int main(void)
{
printf("size = %d = %d\n", SIZEOF_INT_AS_STR, SIZEOF_INT_AS_STR_1);
printf("INT_MAX = %d\n", INT_MAX);
printf("UINT_MAX = %u\n", UINT_MAX);
return(0);
}
这甚至不能在带有 GCC 4.0.1 的 MacOS X 10.5.8 上编译 - 因为标识符 INT_MAX 没有定义。未打印 INT_MAX 或 UINT_MAX 的代码的初步版本有效;它表明 SIZEOF_INT_AS_STR_1 的值是 31 - 所以 @caf 是正确的。添加对INT_MAX 和UINT_MAX 值的双重检查然后编译失败,这让我感到惊讶。看看gcc -E 的输出就会发现原因:
enum { SIZEOF_INT_AS_STR = sizeof("4294967295,")-1 };
enum { SIZEOF_INT_AS_STR_1 = sizeof("((-INT_MAX - 1)-1 - 100 + 100)" ",")-1 };
int main(void)
{
printf("size = %d = %d\n", SIZEOF_INT_AS_STR, SIZEOF_INT_AS_STR_1);
printf("INT_MAX = %d\n", ((-INT_MAX - 1)-1 - 100 + 100));
printf("UINT_MAX = %u\n", (((-INT_MAX - 1)-1 - 100 + 100) * 2U + 1U));
return(0);
}
正如预测的那样,SIZEOF_IN_AS_STR_1 的字符串根本不是数字字符串。预处理器可以评估表达式(尽可能多地),但不必生成数字字符串。
INT_MAX 的扩展原来是根据INT_MIN 来定义的,而INT_MIN 反过来又是根据INT_MAX 定义的,所以当评估重写的INT_MAX 宏时,' C 预处理器的操作规则阻止了递归扩展,并且 INT_MAX 出现在预处理输出中 - 让所有人感到困惑。
因此,表面上吸引人的想法被证明是个坏主意的原因有很多。