Waar is de itoa-functie in Linux?

itoa()is een erg handige functie om een getal om te zetten in een string. Linux lijkt itoa()niet te hebben, is er een equivalente functie of moet ik sprintf(str, "%d", num)gebruiken?


Antwoord 1, autoriteit 100%

EDIT: Sorry, ik had moeten onthouden dat deze machine beslist niet-standaard is, omdat ik verschillende niet-standaard libc-implementaties heb aangesloten voor academische doeleinden 😉

Aangezien itoa()inderdaad niet-standaard is, zoals vermeld door verschillende behulpzame commentatoren, is het het beste om sprintf(target_string,"%d",source_int)te gebruiken of (beter nog, omdat het veilig is voor bufferoverlopen) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). Ik weet dat het niet zo beknopt of cool is als itoa(), maar je kunt tenminste één keer schrijven, overal uitvoeren ™ 😉

Hier is het oude (bewerkte) antwoord

Je hebt gelijk als je stelt dat de standaard gcc libcitoa()niet bevat, zoals verschillende andere platforms, omdat het technisch gezien geen deel uitmaakt van de standaard . Zie hiervoor wat meer informatie. Merk op dat je moet

#include <stdlib.h>

Natuurlijk weet je dit al, want je wilde gebruikenitoa()op Linux nadat je het vermoedelijk op een ander platform had gebruikt, maar… de code (gestolen van de bovenstaande link) zou er als volgt uitzien:

Voorbeeld

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

Uitvoer:

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

Hopelijk helpt dit!


Antwoord 2, autoriteit 18%

itoais niet een standaard C-functie. U kunt uw eigen uitvoeren. Het verscheen in de eerste editie van Kernighanen Ritchie’sThe C Programming Language, op pagina 60. De tweede editie van The C Programming Language (” K&R2″) bevat de volgende implementatie van itoa, op pagina 64. Het boek vermeldt verschillende problemen met deze implementatie, waaronder het feit dat het niet correct omgaat met het meest negatieve getal

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

De hierboven gebruikte functie reverseis twee pagina’s eerder geïmplementeerd:

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

Antwoord 3, autoriteit 11%

Als je het veel roept, kan het advies van “gebruik gewoon snprintf” vervelend zijn. Dus dit is wat je waarschijnlijk wilt:

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

Antwoord 4, autoriteit 8%

Bewerken:ik hoorde net over std::to_stringdie in werking identiek is aan mijn eigen functie hieronder. Het werd geïntroduceerd in C++11 en is beschikbaar in recente versies van gcc, in ieder geval al vanaf 4.5 als je de c++0x-extensies inschakelt.


Niet alleen ontbreekt itoain gcc, het is ook niet de handigste functie om te gebruiken, omdat je het een buffer moet geven. Ik had iets nodig dat in een uitdrukking kon worden gebruikt, dus bedacht ik dit:

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

Normaal gesproken zou het veiliger zijn om snprintfte gebruiken in plaats van sprintf, maar de buffer is zorgvuldig gedimensioneerd om immuun te zijn voor overschrijding.

Zie een voorbeeld: http://ideone.com/mkmzve


5, Autoriteit 6%

Zoals MATT J schreef, is er itoa, maar het is niet standaard. Uw code is draagbaar als u snprintfgebruikt.


6, Autoriteit 4%

De volgende functie wijst net genoeg geheugen toe om de reeksvertegenwoordiging van het gegeven nummer te houden en schrijft vervolgens de tekenreeksweergave op dit gebied met behulp van de standaard sprintf-methode.

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

Vergeet niet op freeUP TOEGEWEZEN MEMOREN INDIEN OF NODIGHEID:

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

n.b. Aangezien SNPRINTF N-1 bytes kopieert, moeten we SNPRINTF (BUF, LEN + 1, “% LD”, N) bellen (niet alleen SNPRINTF (BUF, LEN, “% LD”, N))


7, Autoriteit 4%

Het lezen van de code van jongens die het voor de kost doen, krijgt u een lange weg.

Bekijk hoe jongens van MySQL het deed. De bron is zeer goed opmerkingen en leert u veel meer dan gehackte oplossingen die overal op de plaats staan.

MySQL’s implementatie van int2str

Ik geef hier de genoemde implementatie; De link is hier voor referentie en moet worden gebruikt om de volledige implementatie te lezen.

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

Antwoord 8, autoriteit 4%

Waar is de itoa-functie in Linux?

Er is geen dergelijke functie in Linux. Ik gebruik in plaats daarvan deze code.

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

Antwoord 9, autoriteit 3%

ik heb mijn eigen implementatie van itoa() geprobeerd, het lijkt te werken in binair, octaal, decimaal en hex

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

10, Autoriteit 2%

Directe kopie naar buffer: 64 Bit Integer 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];
    }

opmerking: verander long in long long voor 32-bits machine. long to int voor 32 bit integer. m is de radix. Als u de radix verkleint, verhoogt u het aantal tekens (variabele i). Als u de radix vergroot, verlaag dan het aantal tekens (beter). In het geval van een niet-ondertekend gegevenstype, wordt ik gewoon 16 + 1.


Antwoord 11, autoriteit 2%

Hier is een sterk verbeterde versie van Archana’s oplossing. Het werkt voor elke radix 1-16 en getallen <= 0, en het zou het geheugen niet moeten beroven.

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

12, Autoriteit 2%

Als u ze gewoon wilt afdrukken:

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

Antwoord 13, autoriteit 2%

glibc interne implementatie

glibc 2.28 heeft een interne implementatie:

die intern op verschillende plaatsen wordt gebruikt, maar ik kon niet vinden of het kan worden blootgesteld of hoe.

Dat zou tenminste een robuuste implementatie moeten zijn als je bereid bent om het te extraheren.

Deze vraag vraagt hoe u uw eigen kunt rollen: Hoe u converteer een int naar string in C?


Antwoord 14, autoriteit 2%

Ik heb liever dit: https://github.com/wsq003/itoa_for_linux

Het zou de snelste itoa() ooit moeten zijn. We gebruiken itoa() in plaats van sprintf() om prestatieredenen, dus een snelste itoa() met beperkte functionaliteit is redelijk en de moeite waard.


Antwoord 15

De vervanging met snprintf is NIET compleet!

Het dekt alleen basen: 2, 8, 10, 16, terwijl itoa werkt voor bases tussen 2 en 36.

Omdat ik op zoek was naar een vervanging voor base 32, denk ik dat ik die van mezelf moet coderen!


Antwoord 16

Ik heb _itoa(…) gebruikt op RedHat 6 en GCC-compiler. Het werkt.


Antwoord 17

Je kunt dit programma gebruiken in plaats van 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);
}

Other episodes