¿Dónde está la función itoa en Linux?


139

itoa()Es una función realmente útil para convertir un número en una cadena. Linux no parece tener itoa(), ¿hay una función equivalente o debo usarla sprintf(str, "%d", num)?


44
alguna razón para no usar sprintf(str, "%d", num)? ¿es mucho más lento que itoa?
desarrollado el

1
@javapowered, por ejemplo, itoapermite la conversión de base arbitraria, los printfespecificadores no.
vladr

@javapowered sprintf () no es señal segura
lunesco

¿Alguna razón para no usar gcvt()de la biblioteca estándar?
Subin Sebastian

Respuestas:


100

EDITAR: Lo siento, debería haber recordado que esta máquina es decididamente no estándar, después de haber conectado varias libcimplementaciones no estándar para fines académicos ;-)

Como de itoa()hecho no es estándar, como lo mencionaron varios comentaristas útiles, es mejor usar sprintf(target_string,"%d",source_int)o (mejor aún, porque está a salvo de desbordamientos del búfer) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). Sé que no es tan conciso o genial como itoa(), pero al menos puedes escribir una vez, correr en todas partes (tm) ;-)

Aquí está la vieja respuesta (editada)

Tiene razón al afirmar que el valor predeterminado gcc libcno incluye itoa(), como muchas otras plataformas, debido a que técnicamente no forma parte del estándar. Vea aquí para un poco más de información. Tenga en cuenta que tiene que

#include <stdlib.h>

Por supuesto, ya lo sabe, porque quería usarlo itoa() en Linux después de presumiblemente usarlo en otra plataforma, pero ... el código (robado del enlace anterior) se vería así:

Ejemplo

/* 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;
}

Salida:

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

¡Espero que esto ayude!


1
Hmmm, compilar eso en Debian me da "referencia indefinida a 'itoa'". Tal vez algo está mal con mi sistema.
Adam Pierce

Me sale lo mismo en Ubuntu 8.04. No puedo encontrar ninguna referencia a itoa en stdio.h o stdlib.h tampoco (no es sorprendente ya que no es parte del estándar)
camh

editado para la corrección, gracias chicos! lo siento, siempre olvido que esto no es una caja de Linux vainilla ;-)
Matt J

He editado la respuesta para incluir el argumento del tamaño del búfer; Creo que todo está como debería estar ahora, no veo un problema con el orden de los argumentos per se. ¿Me estoy perdiendo de algo?
Matt J

¿No funciona para Linux? ¿cuál es el resultado de la pregunta / respuesta (no estándar parece ser todos Linuxes?)

12

Si lo estás llamando mucho, el consejo de "solo usa snprintf" puede ser molesto. Entonces, esto es lo que probablemente quieras:

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
como dice el comentario :)
James Antill

17
No solo no es seguro para subprocesos, tampoco es muy seguro: - void some_func (char * a, char * b); some_func (itoa (123), itoa (456)); ¿Te importa adivinar qué recibe la función?
jcoder

Además, los constcalificadores no hacen nada en los tipos de retorno de funciones; lo sabría si activara las advertencias del compilador :)
cat

3
@cat Pero aquí no hay ningún tipo de retorno calificado const. const char *es un puntero no constante a const, lo que tiene mucho sentido y es correcto.
Chortos-2

1
@ Chortos-2 Eso es interesante, usted es, por supuesto, completamente correcto: no me di cuenta de la diferencia semántica en el significado de constentre const int f (void) { ...y const int* f (void) { ..., pero ahora que lo he intentado con un compilador, tiene sentido.
gato

11

itoano es una función estándar de C. Puedes implementar el tuyo. Apareció en la primera edición de Kernighan y The C Programming Language Ritchie , en la página 60. La segunda edición de The C Programming Language ("K & R2") contiene la siguiente implementación de itoa, en la página 64. El libro señala varios problemas con esta implementación , incluido el hecho de que no maneja correctamente el número más negativo

 /* 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);
}  

La función reverse utilizada anteriormente se implementa dos páginas antes:

 #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;
     }
}  

8

Editar: me acabo de enterar destd::to_string cuál es idéntico en operación a mi propia función a continuación. Se introdujo en C ++ 11 y está disponible en versiones recientes de gcc, al menos tan pronto como 4.5 si habilita las extensiones de c ++ 0x.


No solo itoafalta gcc, no es la función más práctica de usar, ya que necesita alimentarlo con un búfer. Necesitaba algo que pudiera usarse en una expresión, así que se me ocurrió esto:

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

Por lo general, sería más seguro usarlo en snprintflugar de hacerlo, sprintfpero el tampón está cuidadosamente dimensionado para ser inmune al desbordamiento.

Vea un ejemplo: http://ideone.com/mKmZVE


12
La pregunta parece ser sobre C, que no tiene std::cosas, etc.
glglgl

6

Como Matt J escribió, la hay itoa, pero no es estándar. Su código será más portátil si lo usa snprintf.


4

La siguiente función asigna la memoria suficiente para mantener la representación de cadena del número dado y luego escribe la representación de cadena en esta área utilizando el sprintfmétodo estándar .

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;
}

No olvide freeaumentar la memoria asignada cuando sea necesario:

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

NB Como snprintf copia n-1 bytes, tenemos que llamar a snprintf (buf, len + 1, "% ld", n) (no solo snprintf (buf, len, "% ld", n))


44
No es una buena idea llamar a su función, itoapero darle un comportamiento diferente al que itoatienen en realidad las implementaciones comunes . Esta función es una buena idea, pero llámela de otra manera :) También sugeriría usar snprintfpara calcular la longitud del búfer en lugar de la cadena de punto flotante; el punto flotante puede tener imprecisiones de mayúsculas y minúsculas. Y no lanzar calloc
MM

Gracias por las sugerencias
mmdemirbas

Esto debería usarse labssi va a tomar un número entero largo. De lo contrario, podría truncarse.
Schwern

snprintfen un búfer tmp de tamaño fijo como char buf[64]para obtener la longitud, luego mallocy copiar en eso. Que no está recibiendo ningún beneficio de callocmás malloc, ya que se escribe todos los bytes. Copiar extra de una cadena muy corta es menos malo que tener que llamar log10 de coma flotante. Sin embargo, una aproximación rápida con un entero log2 podría ser útil si tiene una función de escaneo de bits que se alineará de manera confiable con algo eficiente (como bsren x86). (Alternativa: mallocun búfer de 64 bytes y luego reallocdespués de conocer la longitud final.)
Peter Cordes

3

¿Dónde está la función itoa en Linux?

No existe tal función en Linux. Yo uso este código en su lugar.

/*
=============
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;
}

Debería editar su respuesta para explicar cómo este código responde a la pregunta.
C. Helling

2

probé mi propia implementación de itoa (), parece que funciona en binario, octal, decimal y hexadecimal

#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;
}

1

copia directa al búfer: entero de 64 bits itoa hexadecimal:

    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];
    }

nota: cambie de largo a largo por la máquina de 32 bits. largo a int en caso de un entero de 32 bits. m es la raíz. Al disminuir la raíz, aumente el número de caracteres (variable i). Cuando aumente la raíz, disminuya el número de caracteres (mejor). En caso de tipo de datos sin firmar, me convierto en 16 + 1.


1

Aquí hay una versión mucho mejor de la solución de Archana. Funciona para cualquier raíz 1-16, y números <= 0, y no debería bloquear la memoria.

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

Si solo quieres imprimirlos:

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

Leer el código de los chicos que lo hacen para ganarse la vida te dará un LARGO CAMINO.

Mira cómo lo hicieron los chicos de MySQL. La fuente está MUY BIEN COMENTADA y le enseñará mucho más que las soluciones pirateadas que se encuentran por todas partes.

La implementación de MySQL de int2str

Proporciono la implementación mencionada aquí; el enlace está aquí como referencia y debe usarse para leer la implementación completa.

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
Siempre es bienvenido un enlace a una solución potencial, pero agregue contexto alrededor del enlace para que sus usuarios tengan una idea de qué es y por qué está allí. Siempre cite la parte más relevante de un enlace importante, en caso de que no se pueda acceder al sitio de destino o se desconecte permanentemente. Tenga en cuenta que ser apenas más que un enlace a un sitio externo es una posible razón de por qué y cómo se eliminan algunas respuestas. .
Tunaki

1
Entonces, ¿qué tiene de bueno el fragmento que publicaste aquí? ¿Qué deben tener en cuenta los futuros lectores?
Martijn Pieters

1

¿Dónde está la función itoa en Linux?

Como itoa()no es estándar en C, existen varias versiones con varias firmas de funciones.
char *itoa(int value, char *str, int base);es común en * nix.

Si falta en Linux o si el código no quiere limitar la portabilidad, el código podría hacerlo propio.

A continuación se muestra una versión que no tiene problemas INT_MINy maneja los búferes con problemas: NULLo un búfer insuficiente devuelve 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);
}

A continuación se muestra una versión C99 o posterior que maneja cualquier base [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);
}

Para un código compatible con C89 y posteriores, reemplace el bucle interno con

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


1

Preferiría esto: https://github.com/wsq003/itoa_for_linux

Debería ser el itoa () más rápido de la historia. Usamos itoa () en lugar de sprintf () por razones de rendimiento, por lo que un itoa () más rápido con funciones limitadas es razonable y vale la pena.



0

¡El reemplazo con snprintf NO está completo!

Cubre solo bases: 2, 8, 10, 16, mientras que itoa funciona para bases entre 2 y 36.

Como estaba buscando un reemplazo para la base 32, ¡creo que tendré que codificar el mío!


-4

Puedes usar este programa en lugar de 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);
}

44
Hay tantos errores en este código: 1) En realidad no convierte hexadecimal correctamente. 2) No convierte 0 en absoluto. 3) No funciona con números negativos. 4) No se verifica el desbordamiento del búfer. Publicaré una versión mejorada de este código en breve.
Chris Desjardins
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.