Где находится функция itoa в Linux?


146

itoa()- действительно удобная функция для преобразования числа в строку. В Linux, похоже, нет itoa(), есть ли эквивалентная функция или мне нужно ее использовать sprintf(str, "%d", num)?


4
по какой причине не использовать sprintf(str, "%d", num)? это намного медленнее, чем itoa?
Олег Важнев

1
@javapowered, например, itoaдопускает произвольное базовое преобразование, а printfспецификаторы - нет.
vladr

@javapowered sprintf () небезопасен для сигналов
lunesco

Есть ли причина не использовать gcvt()из стандартной библиотеки?
Субин Себастьян

Ответы:


105

РЕДАКТИРОВАТЬ: Извините, я должен был помнить, что эта машина явно нестандартна, поскольку в нее были включены различные нестандартные libcреализации для академических целей ;-)

Поскольку itoa()это действительно нестандартно, как упоминалось несколькими полезными комментаторами, лучше всего использовать sprintf(target_string,"%d",source_int)или (еще лучше, потому что это безопасно от переполнения буфера) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). Я знаю, что это не так лаконично или круто itoa(), но по крайней мере вы можете написать один раз, запустить везде (tm) ;-)

Вот старый (отредактированный) ответ

Вы правы, утверждая, что стандарт по умолчанию gcc libcне включает itoa(), как некоторые другие платформы, потому что технически он не является частью стандарта. См. Здесь для получения дополнительной информации. Обратите внимание, что вам нужно

#include <stdlib.h>

Конечно, вы уже знаете это, потому что хотели использовать itoa() Linux после того, как предположительно использовали его на другой платформе, но ... код (украденный по ссылке выше) будет выглядеть так:

пример

/* itoa example */
#include <stdio.h>
#include <stdlib.h>

int main ()
{
  int i;
  char buffer [33];
  printf ("Enter a number: ");
  scanf ("%d",&i);
  itoa (i,buffer,10);
  printf ("decimal: %s\n",buffer);
  itoa (i,buffer,16);
  printf ("hexadecimal: %s\n",buffer);
  itoa (i,buffer,2);
  printf ("binary: %s\n",buffer);
  return 0;
}

Выход:

Enter a number: 1750
decimal: 1750
hexadecimal: 6d6
binary: 11011010110

Надеюсь это поможет!


1
Хммм, компиляция этого в Debian дает мне «неопределенную ссылку на ʻitoa '». Может что-то не так с моей системой.
Адам Пирс,

Я получаю то же самое на Ubuntu 8.04. Я также не могу найти ссылки на itoa в stdio.h или stdlib.h (неудивительно, поскольку он не является частью стандарта)
camh

отредактировал для правильности, спасибо, ребята! извините, я всегда забываю, что это не ванильный Linux-бокс ;-)
Мэтт Дж.

Я отредактировал ответ, включив в него аргумент размера буфера; Я считаю, что сейчас все так, как должно быть, я не вижу проблем с порядком аргументов как таковым. Я что-то упускаю?
Matt J

Не работает для Linux? каков результат вопроса / ответа (нестандартные, кажется, все линуксы?)

16

itoaне является стандартной функцией C. Вы можете реализовать свои собственные. Он появился в первом издании языка программирования C Кернигана и Ричи на странице 60. Второе издание языка программирования C («K & R2») содержит следующую реализацию языка программирования C на странице 64. В книге отмечается несколько проблем с этой реализацией. , включая тот факт, что он неправильно обрабатывает самые отрицательные числаitoa

 /* itoa:  convert n to characters in s */
 void itoa(int n, char s[])
 {
     int i, sign;

     if ((sign = n) < 0)  /* record sign */
         n = -n;          /* make n positive */
     i = 0;
     do {       /* generate digits in reverse order */
         s[i++] = n % 10 + '0';   /* get next digit */
     } while ((n /= 10) > 0);     /* delete it */
     if (sign < 0)
         s[i++] = '-';
     s[i] = '\0';
     reverse(s);
}  

reverseИспользуемая выше функция реализована двумя страницами ранее:

 #include <string.h>

 /* reverse:  reverse string s in place */
 void reverse(char s[])
 {
     int i, j;
     char c;

     for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
         c = s[i];
         s[i] = s[j];
         s[j] = c;
     }
}  

12

Если вы часто это называете, совет «просто используйте snprintf» может раздражать. Итак, вот что вы, вероятно, захотите:

const char *my_itoa_buf(char *buf, size_t len, int num)
{
  static char loc_buf[sizeof(int) * CHAR_BITS]; /* not thread safe */

  if (!buf)
  {
    buf = loc_buf;
    len = sizeof(loc_buf);
  }

  if (snprintf(buf, len, "%d", num) == -1)
    return ""; /* or whatever */

  return buf;
}

const char *my_itoa(int num)
{ return my_itoa_buf(NULL, 0, num); }

8
как сказано в комментарии :)
Джеймс Антилл

17
Это не просто небезопасно для потоков, это совсем не безопасно: - void some_func (char * a, char * b); some_func (itoa (123), itoa (456)); Хотите угадать, что получает функция?
jcoder

Кроме того, constквалификаторы ничего не делают с типами, возвращаемыми функцией - вы бы это знали, если бы включили предупреждения компилятора :)
cat

4
@cat Но здесь нет возвращаемых типов с квалификацией const. const char *- неконстантный указатель на const, что имеет большой смысл и является правильным.
Чортос-2

1
@ Chortos-2 Это интересно, вы, конечно, совершенно правы - я не осознавал семантическую разницу в значении constмежду const int f (void) { ...и const int* f (void) { ..., но теперь, попробовав это с компилятором, это имеет смысл.
cat

7

Изменить: я только что узнал, std::to_stringчто работает аналогично моей собственной функции ниже. Он был представлен в C ++ 11 и доступен в последних версиях gcc, по крайней мере, начиная с 4.5, если вы включили расширения c ++ 0x.


Мало того itoa, что в gcc отсутствует, это не самая удобная функция для использования, так как вам нужно заполнить ее буфером. Мне нужно было что-то, что можно было бы использовать в выражении, поэтому я придумал следующее:

std::string itos(int n)
{
   const int max_size = std::numeric_limits<int>::digits10 + 1 /*sign*/ + 1 /*0-terminator*/;
   char buffer[max_size] = {0};
   sprintf(buffer, "%d", n);
   return std::string(buffer);
}

Обычно было бы безопаснее использовать snprintfвместо этого, sprintfно размер буфера тщательно подбирается, чтобы не допустить переполнения.

См. Пример: http://ideone.com/mKmZVE


13
Вопрос, похоже, касается C, в котором нет std::материала и т. Д.
glglgl

6

Как написал Мэтт Дж., Есть itoa, но это не стандарт. Ваш код будет более переносимым, если вы будете использовать snprintf.


4

Следующая функция выделяет достаточно памяти, чтобы сохранить строковое представление данного числа, а затем записывает строковое представление в эту область стандартным sprintfметодом.

char *itoa(long n)
{
    int len = n==0 ? 1 : floor(log10l(labs(n)))+1;
    if (n<0) len++; // room for negative sign '-'

    char    *buf = calloc(sizeof(char), len+1); // +1 for null
    snprintf(buf, len+1, "%ld", n);
    return   buf;
}

Не забывайте freeувеличивать выделенную память, когда она не нужна:

char *num_str = itoa(123456789L);
// ... 
free(num_str);

NB Поскольку snprintf копирует n-1 байтов, мы должны вызвать snprintf (buf, len + 1, "% ld", n) (а не только snprintf (buf, len, "% ld", n))


4
Не рекомендуется вызывать вашу функцию, itoaно нужно дать ей другое поведение по сравнению с обычными реализациями itoa. Эта функция - хорошая идея, но назовите ее по-другому :) Я бы также предложил использовать snprintfдля расчета длины буфера вместо строки с плавающей запятой; с плавающей запятой могут быть неточности в углу. And don't cast calloc
MM

Спасибо за предложения.
mmdemirbas

Это следует использовать, labsесли требуется длинное целое число. В противном случае он может быть усечен.
Schwern

snprintfв буфер tmp фиксированного размера, например, char buf[64]чтобы получить длину, а затем mallocскопировать в него. Вы не получите никакой пользы от callocзавершения malloc, поскольку вы записываете все байты. Дополнительное копирование очень короткой строки менее опасно, чем вызов log10 с плавающей запятой. Однако быстрое приближение с целым числом log2 может быть полезно, если у вас есть функция битового сканирования, которая будет надежно встроена в что-то эффективное (например, bsrна x86). (Альтернатива: malloc64-байтовый буфер, а затем, reallocкогда вы знаете окончательную длину.)
Питер Кордес,

3

Где находится функция itoa в Linux?

В Linux такой функции нет. Вместо этого я использую этот код.

/*
=============
itoa

Convert integer to string

PARAMS:
- value     A 64-bit number to convert
- str       Destination buffer; should be 66 characters long for radix2, 24 - radix8, 22 - radix10, 18 - radix16.
- radix     Radix must be in range -36 .. 36. Negative values used for signed numbers.
=============
*/

char* itoa (unsigned long long  value,  char str[],  int radix)
{
    char        buf [66];
    char*       dest = buf + sizeof(buf);
    boolean     sign = false;

    if (value == 0) {
        memcpy (str, "0", 2);
        return str;
    }

    if (radix < 0) {
        radix = -radix;
        if ( (long long) value < 0) {
            value = -value;
            sign = true;
        }
    }

    *--dest = '\0';

    switch (radix)
    {
    case 16:
        while (value) {
            * --dest = '0' + (value & 0xF);
            if (*dest > '9') *dest += 'A' - '9' - 1;
            value >>= 4;
        }
        break;
    case 10:
        while (value) {
            *--dest = '0' + (value % 10);
            value /= 10;
        }
        break;

    case 8:
        while (value) {
            *--dest = '0' + (value & 7);
            value >>= 3;
        }
        break;

    case 2:
        while (value) {
            *--dest = '0' + (value & 1);
            value >>= 1;
        }
        break;

    default:            // The slow version, but universal
        while (value) {
            *--dest = '0' + (value % radix);
            if (*dest > '9') *dest += 'A' - '9' - 1;
            value /= radix;
        }
        break;
    }

    if (sign) *--dest = '-';

    memcpy (str, dest, buf +sizeof(buf) - dest);
    return str;
}

Вы должны отредактировать свой ответ, чтобы объяснить, как этот код отвечает на вопрос.
К. Хеллинг

2

Я пробовал свою собственную реализацию itoa (), похоже, работает в двоичном, восьмеричном, десятичном и шестнадцатеричном форматах

#define INT_LEN (10)
#define HEX_LEN (8)
#define BIN_LEN (32)
#define OCT_LEN (11)

static char *  my_itoa ( int value, char * str, int base )
{
    int i,n =2,tmp;
    char buf[BIN_LEN+1];


    switch(base)
    {
        case 16:
            for(i = 0;i<HEX_LEN;++i)
            {
                if(value/base>0)
                {
                    n++;
                }
            }
            snprintf(str, n, "%x" ,value);
            break;
        case 10:
            for(i = 0;i<INT_LEN;++i)
            {
                if(value/base>0)
                {
                    n++;
                }
            }
            snprintf(str, n, "%d" ,value);
            break;
        case 8:
            for(i = 0;i<OCT_LEN;++i)
            {
                if(value/base>0)
                {
                    n++;
                }
            }
            snprintf(str, n, "%o" ,value);
            break;
        case 2:
            for(i = 0,tmp = value;i<BIN_LEN;++i)
            {
                if(tmp/base>0)
                {
                    n++;
                }
                tmp/=base;
            }
            for(i = 1 ,tmp = value; i<n;++i)
            {
                if(tmp%2 != 0)
                {
                    buf[n-i-1] ='1';
                }
                else
                {
                    buf[n-i-1] ='0';
                }
                tmp/=base;
            }
            buf[n-1] = '\0';
            strcpy(str,buf);
            break;
        default:
            return NULL;
    }
    return str;
}

2

Чтение кодекса парней, которые этим зарабатывают на жизнь, даст вам ДОЛГОЙ ПУТЬ.

Посмотрите, как это сделали ребята из MySQL. Источник ОЧЕНЬ ХОРОШО КОММЕНТАРИАН и научит вас гораздо большему, чем взломанные решения, которые можно найти повсюду.

Реализация MySQL для int2str

Я предоставляю указанную реализацию здесь; ссылка здесь для справки, и ее следует использовать для чтения полной реализации.

char *
int2str(long int val, char *dst, int radix, 
        int upcase)
{
  char buffer[65];
  char *p;
  long int new_val;
  char *dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower;
  ulong uval= (ulong) val;

  if (radix < 0)
  {
    if (radix < -36 || radix > -2)
      return NullS;
    if (val < 0)
    {
      *dst++ = '-';
      /* Avoid integer overflow in (-val) for LLONG_MIN (BUG#31799). */
      uval = (ulong)0 - uval;
    }
    radix = -radix;
  }
  else if (radix > 36 || radix < 2)
    return NullS;

  /*
    The slightly contorted code which follows is due to the fact that
    few machines directly support unsigned long / and %.  Certainly
    the VAX C compiler generates a subroutine call.  In the interests
    of efficiency (hollow laugh) I let this happen for the first digit
    only; after that "val" will be in range so that signed integer
    division will do.  Sorry 'bout that.  CHECK THE CODE PRODUCED BY
    YOUR C COMPILER.  The first % and / should be unsigned, the second
    % and / signed, but C compilers tend to be extraordinarily
    sensitive to minor details of style.  This works on a VAX, that's
    all I claim for it.
  */
  p = &buffer[sizeof(buffer)-1];
  *p = '\0';
  new_val= uval / (ulong) radix;
  *--p = dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)];
  val = new_val;
  while (val != 0)
  {
    ldiv_t res;
    res=ldiv(val,radix);
    *--p = dig_vec[res.rem];
    val= res.quot;
  }
  while ((*dst++ = *p++) != 0) ;
  return dst-1;
}

1
Ссылка на потенциальное решение всегда приветствуется, но, пожалуйста, добавьте контекст вокруг ссылки, чтобы ваши друзья-пользователи имели некоторое представление о том, что это такое и почему. Всегда указывайте наиболее релевантную часть важной ссылки на случай, если целевой сайт недоступен или постоянно отключен. Учтите, что возможная причина того, почему и как удаляются некоторые ответы, - это просто ссылка на внешний сайт ? .
Tunaki

1
Так что же такого хорошего в размещенном здесь фрагменте? На что следует обратить внимание будущим читателям?
Мартейн Питерс

1

прямая копия в буфер: 64-битное целое число itoa hex:

    char* itoah(long num, char* s, int len)
    {
            long n, m = 16;
            int i = 16+2;
            int shift = 'a'- ('9'+1);


            if(!s || len < 1)
                    return 0;

            n = num < 0 ? -1 : 1;
            n = n * num;

            len = len > i ? i : len;
            i = len < i ? len : i;

            s[i-1] = 0;
            i--;

            if(!num)
            {
                    if(len < 2)
                            return &s[i];

                    s[i-1]='0';
                    return &s[i-1];
            }

            while(i && n)
            {
                    s[i-1] = n % m + '0';

                    if (s[i-1] > '9')
                            s[i-1] += shift ;

                    n = n/m;
                    i--;
            }

            if(num < 0)
            {
                    if(i)
                    {
                            s[i-1] = '-';
                            i--;
                    }
            }

            return &s[i];
    }

примечание: измените long на long для 32-битной машины. long в int в случае 32-битного целого числа. m - основание системы счисления. При уменьшении системы счисления увеличивайте количество символов (переменная i). При увеличении системы счисления уменьшите количество знаков (лучше). В случае беззнакового типа данных i просто становится 16 + 1.


1

Вот значительно улучшенная версия решения Archana. Он работает для любых оснований системы счисления 1-16 и чисел <= 0, и он не должен стирать память.

static char _numberSystem[] = "0123456789ABCDEF";
static char _twosComp[] = "FEDCBA9876543210";

static void safestrrev(char *buffer, const int bufferSize, const int strlen)
{
    int len = strlen;
    if (len > bufferSize)
    {
        len = bufferSize;
    }
    for (int index = 0; index < (len / 2); index++)
    {
        char ch = buffer[index];
        buffer[index] = buffer[len - index - 1];
        buffer[len - index - 1] = ch;
    }
}

static int negateBuffer(char *buffer, const int bufferSize, const int strlen, const int radix)
{
    int len = strlen;
    if (len > bufferSize)
    {
        len = bufferSize;
    }
    if (radix == 10)
    {
        if (len < (bufferSize - 1))
        {
            buffer[len++] = '-';
            buffer[len] = '\0';
        }
    }
    else
    {
        int twosCompIndex = 0;
        for (int index = 0; index < len; index++)
        {
            if ((buffer[index] >= '0') && (buffer[index] <= '9'))
            {
                twosCompIndex = buffer[index] - '0';
            }
            else if ((buffer[index] >= 'A') && (buffer[index] <= 'F'))
            {
                twosCompIndex = buffer[index] - 'A' + 10;
            }
            else if ((buffer[index] >= 'a') && (buffer[index] <= 'f'))
            {
                twosCompIndex = buffer[index] - 'a' + 10;
            }
            twosCompIndex += (16 - radix);
            buffer[index] = _twosComp[twosCompIndex];
        }
        if (len < (bufferSize - 1))
        {
            buffer[len++] = _numberSystem[radix - 1];
            buffer[len] = 0;
        }
    }
    return len;
}

static int twosNegation(const int x, const int radix)
{
    int n = x;
    if (x < 0)
    {
        if (radix == 10)
        {
            n = -x;
        }
        else
        {
            n = ~x;
        }
    }
    return n;
}

static char *safeitoa(const int x, char *buffer, const int bufferSize, const int radix)
{
    int strlen = 0;
    int n = twosNegation(x, radix);
    int nuberSystemIndex = 0;

    if (radix <= 16)
    {
        do
        {
            if (strlen < (bufferSize - 1))
            {
                nuberSystemIndex = (n % radix);
                buffer[strlen++] = _numberSystem[nuberSystemIndex];
                buffer[strlen] = '\0';
                n = n / radix;
            }
            else
            {
                break;
            }
        } while (n != 0);
        if (x < 0)
        {
            strlen = negateBuffer(buffer, bufferSize, strlen, radix);
        }
        safestrrev(buffer, bufferSize, strlen);
        return buffer;
    }
    return NULL;
}

1

Если вы просто хотите их распечатать:

void binary(unsigned int n)
{
    for(int shift=sizeof(int)*8-1;shift>=0;shift--)
    {
       if (n >> shift & 1)
         printf("1");
       else
         printf("0");

    }
    printf("\n");
} 

1

Где находится функция itoa в Linux?

Поскольку itoa()это не является стандартом для C, существуют различные версии с различными сигнатурами функций.
char *itoa(int value, char *str, int base);часто встречается в * nix.

Если он отсутствует в Linux или код не хочет ограничивать переносимость, код может сделать его своим.

Ниже представлена ​​версия, которая не имеет проблем INT_MINи обрабатывает проблемные буферы: NULLили возвращается недостаточный буфер NULL.

#include <stdlib.h>
#include <limits.h>
#include <string.h>

// Buffer sized for a decimal string of a `signed int`, 28/93 > log10(2)
#define SIGNED_PRINT_SIZE(object)  ((sizeof(object) * CHAR_BIT - 1)* 28 / 93 + 3)

char *itoa_x(int number, char *dest, size_t dest_size) {
  if (dest == NULL) {
    return NULL;
  }

  char buf[SIGNED_PRINT_SIZE(number)];
  char *p = &buf[sizeof buf - 1];

  // Work with negative absolute value
  int neg_num = number < 0 ? number : -number;

  // Form string
  *p = '\0';
  do {
    *--p = (char) ('0' - neg_num % 10);
    neg_num /= 10;
  } while (neg_num);
  if (number < 0) {
    *--p = '-';
  }

  // Copy string
  size_t src_size = (size_t) (&buf[sizeof buf] - p);
  if (src_size > dest_size) {
    // Not enough room
    return NULL;
  }
  return memcpy(dest, p, src_size);
}

Ниже представлена ​​версия C99 или более поздняя, ​​которая обрабатывает любую базу [2 ... 36]

char *itoa_x(int number, char *dest, size_t dest_size, int base) {
  if (dest == NULL || base < 2 || base > 36) {
    return NULL;
  }

  char buf[sizeof number * CHAR_BIT + 2]; // worst case: itoa(INT_MIN,,,2)
  char *p = &buf[sizeof buf - 1];

  // Work with negative absolute value to avoid UB of `abs(INT_MIN)`
  int neg_num = number < 0 ? number : -number;

  // Form string
  *p = '\0';
  do {
    *--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(neg_num % base)];
    neg_num /= base;
  } while (neg_num);
  if (number < 0) {
    *--p = '-';
  }

  // Copy string
  size_t src_size = (size_t) (&buf[sizeof buf] - p);
  if (src_size > dest_size) {
    // Not enough room
    return NULL;
  }
  return memcpy(dest, p, src_size);
}

Для кода, совместимого с C89 и последующими версиями, замените внутренний цикл на

  div_t qr;
  do {
    qr = div(neg_num, base);
    *--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
    neg_num = qr.quot;
  } while (neg_num);

1

внутренняя реализация glibc

glibc 2.28 имеет внутреннюю реализацию:

который используется в нескольких местах внутри компании, но я не мог найти, можно ли его раскрыть и как.

По крайней мере, это должна быть надежная реализация, если вы хотите ее извлечь.

В этом вопросе задается вопрос, как свернуть свой собственный: как преобразовать int в строку в C?


1

Я бы предпочел это: https://github.com/wsq003/itoa_for_linux

Это должен быть самый быстрый itoa () когда-либо. Мы используем itoa () вместо sprintf () по соображениям производительности, поэтому самый быстрый itoa () с ограниченной функцией является разумным и целесообразным.



0

Замена на snprintf НЕ завершена!

Он охватывает только базы: 2, 8, 10, 16, тогда как itoa работает для баз от 2 до 36.

Поскольку я искал замену для базы 32, думаю, мне придется написать собственный код!


-4

Вы можете использовать эту программу вместо sprintf.

void itochar(int x, char *buffer, int radix);

int main()
{
    char buffer[10];
    itochar(725, buffer, 10);
    printf ("\n %s \n", buffer);
    return 0;
}

void itochar(int x, char *buffer, int radix)
{
    int i = 0 , n,s;
    n = s;
    while (n > 0)
    {
        s = n%radix;
        n = n/radix;
        buffer[i++] = '0' + s;
    }
    buffer[i] = '\0';
    strrev(buffer);
}

4
В этом коде так много ошибок: 1) На самом деле не преобразовывает шестнадцатеричный код правильно. 2) вообще не преобразует 0. 3) Не работает с отрицательными числами. 4) Отсутствие проверки переполнения буфера. Вскоре я опубликую улучшенную версию этого кода.
Крис Дежарден
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.