snprintf, для преобразования целого числа в строку в C
У меня есть небольшой фрагмент кода для преобразования целого числа в строку в c.
Код должен работать как на 32-битной, так и на 64-битной платформе.
Я разбираю аргументы в цикле, поэтому мне нужен malloc для создания буфера
int tmp_integer = /*read as integer*/
char* tmp_string = malloc(20* sizeof(char)); /*enough room for the biggest integer*/
snprintf(tmp_string, 20,"%d",tmp_integer); /*can I avoid using 20 here*/
a[i - 1] = tmp_string; /*save the parsed argument for final usage*/
Мой вопрос таков: :
Есть ли способ сделать его приятным с помощью snprintf, или я должен вернуться к sprintf.
Я решил, что использование snprintf не было правильным решением, потому что изначально я хотел быть защищенным от переполнения буфера, но поскольку размер целое число известно, я думаю, что это бесполезно. Тем не менее, я хотел бы знать, что является лучшей практикой здесь.
6 ответов:
В данном случае вы правы. Вы знаете, что ваш номер не больше 64 бит, и вы знаете, что это означает, что он не будет иметь более 20 цифр. Поэтому на самом деле вам не нужно использовать
snprintf.Ошибка: самое большое беззнаковое 64-разрядное число, которое у вас может быть, - это 18,446,744,073,709,551,615, что составляет 20 цифр. Однако каждая строка имеет
'\0'(NUL) символ в конце (отсюда терминология строки с нулевым окончанием). Поэтому следует выделить 21 байт для вашего массива, а не 20.
Если вы выделяете память динамически, вы можете использовать log10 для вычисления количества мест, необходимых в вашей строке:
int tmp_integer = /*read as integer*/ int signpadding = 0; if tmpinteger < 0 then signpadding = 1; int digitcount = (integer)floor(log10(abs(value)))+ 1 + signpadding; char* tmp_string = malloc(digitcount * sizeof(char)); snprintf(tmp_string, digitcount,"%d",tmp_integer);
Возникает вопрос, откуда взялась эта волшебная "20". Поскольку он магический, его следует представлять в виде символьной константы, а не целого литерала, повторяющегося в коде. Использование символьной константы также имеет то преимущество, что компилятор выполняет проверку ошибок за вас:
#define MAX_INTEGER_DIGITS (20) int value = /* ... */ char* tmp_string = malloc(MAX_INTEGER_DIGITS); snprintf(tmp_string, MAX_INTEGER_DIGITS, "%d", value);(Также обратите внимание, как я бросил
sizeof (char)вещь, так как это совершенно избыточно и (Имо) очень беспорядочно.)С точки зрения производительности, вы, вероятно, можете отказаться от защищенного варианта форматер строк, но так как вы вызываете
malloc()здесь в любом случае (не дешево), вероятно, это не большая победа, чтобы удалить его.
Вы можете sprintf в временном буфере, а затем выделить хороший размер (с возвратом sprintf), а затем скопировать temp в буфер.
int tmp_integer = /*read as integer*/ static char tmp_string[20]; int size = sprintf(tmp_string,"%d",tmp_integer); char *myValueString = malloc((size+1)*sizeof(char)); a[i - 1] = strcpy(myValueString,tmp_string);
Это еще один (может быть, не очень красивый) способ преобразовать его на основеsum1stolemyname фрагмент кода:
char *convert_int_to_string(int value) { int digitcount; char * tmp_string; int increment = 2; // one for rounding, one for '\0' terminator if(value <0){ increment += 1; // make room for sign } if(0 == value){ tmp_string = malloc(2* sizeof(char)); sprintf(tmp_string, "%u", 0); } else{ digitcount = (int)floor(log10((double)abs(value)))+ increment; tmp_string = malloc(digitcount * sizeof(char)); sprintf(tmp_string, "%d", value); } return tmp_string; }
Простое, переносимое (через различные разрядности, платформы и процессоры) решение этой проблемы:
int tmp_integer = /*read as integer*/ const size_t len = 4 * sizeof(int); char tmp_string[len]; snprintf(tmp_string, len, "%d", tmp_integer);
Comments