Как насчет этого?
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-разрядными целыми числами без знака; если они могут быть больше, тогда enum нуждается в соответствующей корректировке.
Проверенный код:
#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 Пэйт: хорошая идея - да, вы могли бы сделать это довольно эффективно. На самом деле, здесь есть две интересные идеи: использование конкатенации строк с помощью sizeof () (скобки необходимы для ясности - но конкатенация строк происходит достаточно рано, чтобы компилятор не беспокоился) и использование операции stringize в INT_MAX
, - Джонатан Леффлер
Использование операции stringize в INT_MAX
не очень хорошая идея - это просто должно быть «константное выражение», а не обязательно последовательность цифр. Он может быть определен как ((1 << 32) -1) или даже что-то странное, например __int_max, если компилятор позволяет использовать его везде, где вы можете использовать константное выражение. - кафе </p>
И @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);
}
Это даже не компилируется на MacOS X 10.5.8 с GCC 4.0.1 - потому что идентификатор 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
появляется в предварительно обработанном выводе - до путаницы всех.
Итак, есть несколько причин, почему эта внешне привлекательная идея оказывается плохой идеей.