Dov'è la funzione itoa in Linux?


139

itoa()è una funzione davvero utile per convertire un numero in una stringa. Linux non sembra avere itoa(), esiste una funzione equivalente o devo usare sprintf(str, "%d", num)?


4
qualche motivo per non usare sprintf(str, "%d", num)? è molto più lento di itoa?
javapowered il

1
@javapowered, per esempio, itoaconsente una conversione base arbitraria, gli printfspecificatori no.
Vladr,

@javapowered sprintf () non è un segnale sicuro
lunesco

Qualche motivo per non utilizzare gcvt()dalla libreria standard?
Sottomarino Sebastian

Risposte:


100

EDIT: Mi dispiace, avrei dovuto ricordare che questa macchina è decisamente non standard, avendo collegato vari non standard libc implementazioni per scopi accademici ;-)

Dato che in itoa()effetti non è standard, come indicato da numerosi utili commentatori, è meglio utilizzarlo sprintf(target_string,"%d",source_int)o (meglio ancora, perché è al sicuro da buffer overflow) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). So che non è così conciso o bello come itoa(), ma almeno puoi scrivere una volta, corri ovunque (tm) ;-)

Ecco la vecchia risposta (modificata)

Hai ragione nel dichiarare che il default gcc libcnon include itoa(), come molte altre piattaforme, perché tecnicamente non fa parte dello standard. Vedi qui per qualche informazione in più. Nota che devi

#include <stdlib.h>

Ovviamente lo sai già, perché volevi usare itoa() su Linux dopo aver presumibilmente usato su un'altra piattaforma, ma ... il codice (rubato dal link sopra) sarebbe simile a:

Esempio

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

Produzione:

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

Spero che questo ti aiuti!


1
Hmmm, la compilazione che su Debian mi dà "riferimento indefinito a" itoa "". Forse qualcosa non va nel mio sistema.
Adam Pierce,

Ottengo lo stesso su Ubuntu 8.04. Non riesco a trovare alcun riferimento a itoa in stdio.h o stdlib.h (non sorprende dal momento che non fa parte dello standard)
Camh

modificato per correttezza, grazie ragazzi! scusate, dimentico sempre che questa non è una scatola Linux vaniglia ;-)
Matt J

Ho modificato la risposta per includere l'argomento della dimensione del buffer; Credo che tutto sia come dovrebbe essere ora, non vedo un problema con l'ordine degli argomenti di per sé. Mi sto perdendo qualcosa?
Matt J

Non funziona per Linux? qual è il risultato della domanda / risposta (Non standard sembra essere tutto linux?)

12

Se lo chiami molto, il consiglio di "usa solo snprintf" può essere fastidioso. Quindi, ecco quello che probabilmente vuoi:

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
come diceva il commento :)
James Antill il

17
Non è solo non thread-safe, non è affatto sicuro: - void some_func (char * a, char * b); some_func (itoa (123), itoa (456)); Vuoi indovinare cosa riceve la funzione?
jcoder

Inoltre, i constqualificatori non fanno nulla sui tipi di restituzione delle funzioni - lo sapresti se avessi attivato gli avvisi del compilatore :)
cat

3
@cat Ma non ci sono tipi restituiti qualificati qui. const char *è un puntatore non const a const, che ha molto senso ed è corretto.
Chortos-2

1
@ Chortos-2 È interessante, ovviamente hai perfettamente ragione: non avevo capito la differenza semantica nel significato di constBetween const int f (void) { ...e const int* f (void) { ..., ma ora averlo provato con un compilatore, ha senso.
gatto

11

itoanon è una funzione C standard. Puoi implementare il tuo. È apparso nella prima edizione di The C Programming Language di Kernighan e Ritchie , a pagina 60. La seconda edizione di The C Programming Language ("K & R2") contiene la seguente implementazione di , a pagina 64. Il libro rileva diversi problemi con questa implementazione , incluso il fatto che non gestisce correttamente il numero più negativoitoa

 /* 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 funzione reverseutilizzata sopra è stata implementata due pagine prima:

 #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

Modifica: ho appena scopertostd::to_string quale è identico in funzione alla mia funzione di seguito. È stato introdotto in C ++ 11 ed è disponibile nelle recenti versioni di gcc, almeno a partire dalla 4.5 se si abilitano le estensioni c ++ 0x.


Non itoamanca solo in gcc, non è la funzione più pratica da usare poiché è necessario alimentarlo con un buffer. Avevo bisogno di qualcosa che potesse essere usato in un'espressione, quindi ho pensato a questo:

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

Di solito sarebbe più sicuro usare snprintfinvece disprintf ma il buffer è accuratamente dimensionato per essere immune al sovraccarico.

Vedi un esempio: http://ideone.com/mKmZVE


12
La domanda sembra riguardare C, che non ha std::roba ecc.
glglgl

6

Come ha scritto Matt J, c'è itoa, ma non è standard. Il tuo codice sarà più portatile se lo usi snprintf.


4

La seguente funzione alloca memoria sufficiente per mantenere la rappresentazione in forma di stringa del numero dato e quindi scrive la rappresentazione in forma di stringa in quest'area usando il sprintfmetodo standard .

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

Non dimenticare di freeaumentare la memoria allocata quando non è necessario:

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

NB Siccome snprintf copia n-1 byte, dobbiamo chiamare snprintf (buf, len + 1, "% ld", n) (non solo snprintf (buf, len, "% ld", n))


4
Non è una buona idea chiamare la tua funzione itoama dargli un comportamento diverso da quello che le implementazioni comuni itoahanno effettivamente. Questa funzione è un'idea OK ma la chiamo qualcos'altro :) Vorrei anche suggerire di utilizzare snprintfper calcolare la lunghezza del buffer anziché la stringa in virgola mobile; la virgola mobile può avere imprecisioni nella custodia ad angolo. E non lanciare calloc
MM,

Grazie per i suggerimenti
mmdemirbas,

Questo dovrebbe essere usato labsse impiegherà un numero intero lungo. Altrimenti potrebbe troncare.
Schwern,

snprintfin un buffer tmp di dimensioni fisse come char buf[64]ottenere la lunghezza, quindi malloce copiarlo. Non stai ottenendo alcun vantaggio da callocoltre malloc, poiché scrivi tutti i byte. La copia extra di una stringa molto corta è meno dannosa della necessità di chiamare il registro in virgola mobile10. Un'approssimazione rapida con un numero intero log2 potrebbe essere utile, tuttavia, se si dispone di una funzione di scansione bit che si adatterà in modo affidabile a qualcosa di efficiente (come bsrsu x86). (Alternativa: mallocun buffer da 64 byte e poi reallocdopo aver conosciuto la lunghezza finale.)
Peter Cordes

3

Dov'è la funzione itoa in Linux?

Non esiste una tale funzione in Linux. Uso invece questo codice.

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

È necessario modificare la risposta per spiegare come questo codice risponde alla domanda.
C. Helling,

2

ho provato la mia implementazione di itoa (), sembra funzionare in binario, ottale, decimale ed esadecimale

#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 diretta nel buffer: intero a 64 bit 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];
    }

nota: cambia da long a long long per macchine a 32 bit. long to int nel caso di numeri interi a 32 bit. m è la radice. Quando si riduce radix, aumentare il numero di caratteri (variabile i). Quando si aumenta radix, ridurre il numero di caratteri (meglio). In caso di tipo di dati non firmato, divento solo 16 + 1.


1

Ecco una versione molto migliorata della soluzione di Archana. Funziona con qualsiasi radix 1-16 e numeri <= 0 e non dovrebbe ostruire 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

Se vuoi solo stamparli:

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

Leggere il codice dei ragazzi che lo fanno per vivere ti farà fare molta strada.

Scopri come hanno fatto i ragazzi di MySQL. La fonte è MOLTO BEN COMMENTATA e ti insegnerà molto di più delle soluzioni hackerate presenti ovunque.

L'implementazione di MySQL di int2str

Fornisco qui l'implementazione menzionata; il link è qui per riferimento e dovrebbe essere usato per leggere l'implementazione 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
Un collegamento a una potenziale soluzione è sempre il benvenuto, ma ti preghiamo di aggiungere un contesto al collegamento in modo che i tuoi colleghi utenti abbiano idea di cosa sia e perché sia ​​lì. Cita sempre la parte più pertinente di un link importante, nel caso in cui il sito di destinazione non sia raggiungibile o rimanga permanentemente offline. Tieni presente che essere a malapena più di un collegamento a un sito esterno è una possibile ragione del perché e come vengono eliminate alcune risposte? .
Tunaki,

1
Quindi cosa c'è di così bello nello snippet che hai pubblicato qui? Cosa dovrebbero cercare i futuri lettori?
Martijn Pieters

1

Dov'è la funzione itoa in Linux?

Poiché itoa()non è standard in C, esistono varie versioni con varie firme di funzione.
char *itoa(int value, char *str, int base);è comune in * nix.

Se dovesse mancare da Linux o se il codice non vuole limitare la portabilità, il codice potrebbe renderlo proprio.

Di seguito è una versione che non ha problemi con INT_MINe gestisce i buffer dei problemi: NULLoppure viene restituito un buffer insufficiente 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);
}

Di seguito è riportata una versione C99 o successiva che gestisce qualsiasi 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);
}

Per un codice C89 e successivo, sostituire il circuito interno con

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


1

Preferirei questo: https://github.com/wsq003/itoa_for_linux

Dovrebbe essere il più veloce itoa () di sempre. Usiamo itoa () invece di sprintf () per motivi di prestazioni, quindi un itoa () più veloce con funzionalità limitate è ragionevole e utile.



0

La sostituzione con snprintf NON è completa!

Copre solo le basi: 2, 8, 10, 16, mentre itoa funziona per basi tra 2 e 36.

Dato che stavo cercando un sostituto per la base 32, immagino che dovrò codificare il mio!


-4

Puoi usare questo programma invece di 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
Ci sono così tanti bug in questo codice: 1) In realtà non converte correttamente hex. 2) Non converte affatto 0. 3) Non funziona con numeri negativi. 4) Nessun controllo per sovraccarico del buffer. Pubblicherò presto una versione migliorata di questo codice.
Chris Desjardins,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.