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 не было правильным решением, потому что изначально я хотел быть защищенным от переполнения буфера, но поскольку размер целое число известно, я думаю, что это бесполезно. Тем не менее, я хотел бы знать, что является лучшей практикой здесь.

672   6  

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

    Ничего не найдено.