snprintf, для преобразования целых чисел в строки в C - PullRequest
2 голосов
/ 17 октября 2011

У меня есть небольшой кусочек кода для преобразования целого числа в строку в 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 ]

2 голосов
/ 17 октября 2011

Вы правы в этом случае.Вы знаете, что ваш номер не больше 64 бит, и вы знаете, что это означает, что он не будет содержать более 20 цифр.Поэтому вам на самом деле не нужно использовать snprintf.

Ошибка: самое большое 64-разрядное число без знака, которое вы можете получить, составляет 18 446 744 073 709 551 615, то есть 20 цифр.Однако каждая строка имеет в конце символ '\0' (NUL) (отсюда и терминология строки с нулевым символом в конце).Следовательно, вы должны выделить 21 байт для вашего массива, а не 20.

2 голосов
/ 17 октября 2011

Если вы выделяете память динамически, вы можете использовать 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);
1 голос
/ 17 октября 2011

Возникает вопрос, откуда взялись эти магические «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), поскольку она полностью избыточна и (imo) оченьбеспорядок.)

С точки зрения производительности, вы, вероятно, можете покончить с защищенным вариантом строкового форматера, но так как вы все равно вызываете malloc() здесь (не дешево), это, вероятно, не очень хорошовыиграть, чтобы удалить его.

0 голосов
/ 13 июня 2018

Простое, переносимое (для разных битов, платформ и процессоров) решение этой проблемы:

int tmp_integer = /*read as integer*/
const size_t len = 4 * sizeof(int);
char tmp_string[len];
snprintf(tmp_string, len, "%d", tmp_integer);
0 голосов
/ 19 ноября 2012

Это еще один (возможно, не очень красивый) способ преобразования его на основе 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;
}
0 голосов
/ 17 октября 2011

Вы можете sprintf в временном буфере и затем выделить правильный размер (с возвратом sprintf), а затем скопировать временный буфер в ваш буфер.

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); 
...