Where is the itoa function in Linux?

2019-01-01 07:11发布

问题:

itoa() is a really handy function to convert a number to a string. Linux does not seem to have itoa(), is there an equivalent function or do I have to use sprintf(str, \"%d\", num)?

回答1:

EDIT: Sorry, I should have remembered that this machine is decidedly non-standard, having plugged in various non-standard libc implementations for academic purposes ;-)

As itoa() is indeed non-standard, as mentioned by several helpful commenters, it is best to use sprintf(target_string,\"%d\",source_int) or (better yet, because it\'s safe from buffer overflows) snprintf(target_string, size_of_target_string_in_bytes, \"%d\", source_int). I know it\'s not quite as concise or cool as itoa(), but at least you can Write Once, Run Everywhere (tm) ;-)

Here\'s the old (edited) answer

You are correct in stating that the default gcc libc does not include itoa(), like several other platforms, due to it not technically being a part of the standard. See here for a little more info. Note that you have to

#include <stdlib.h>

Of course you already know this, because you wanted to use itoa() on Linux after presumably using it on another platform, but... the code (stolen from the link above) would look like:

Example

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

Output:

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

Hope this helps!



回答2:

If you are calling it a lot, the advice of \"just use snprintf\" can be annoying. So here\'s what you probably want:

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


回答3:

itoa is not a standard C function. You can implement your own. It appeared in the first edition of Kernighan and Ritchie\'s The C Programming Language, on page 60. The second edition of The C Programming Language (\"K&R2\") contains the following implementation of itoa, on page 64. The book notes several issues with this implementation, including the fact that it does not correctly handle the most negative number

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

The function reverse used above is implemented two pages earlier:

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


回答4:

Edit: I just found out about std::to_string which is identical in operation to my own function below. It was introduced in C++11 and is available in recent versions of gcc, at least as early as 4.5 if you enable the c++0x extensions.


Not only is itoa missing from gcc, it\'s not the handiest function to use since you need to feed it a buffer. I needed something that could be used in an expression so I came up with this:

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

Ordinarily it would be safer to use snprintf instead of sprintf but the buffer is carefully sized to be immune to overrun.

See an example: http://ideone.com/mKmZVE



回答5:

As Matt J wrote, there is itoa, but it\'s not standard. Your code will be more portable if you use snprintf.



回答6:

Following function allocates just enough memory to keep string representation of the given number and then writes the string representation into this area using standard sprintf method.

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

Don\'t forget to free up allocated memory when out of need:

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

N.B. As snprintf copies n-1 bytes, we have to call snprintf(buf, len+1, \"%ld\", n) (not just snprintf(buf, len, \"%ld\", n))



回答7:

Here is a much improved version of Archana\'s solution. It works for any radix 1-16, and numbers <= 0, and it shouldn\'t clobber memory.

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


回答8:

Where is the itoa function in Linux?

There is no such function in Linux. I use this code instead.

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


回答9:

direct copy to 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];
    }

note: change long to long long for 32 bit machine. long to int in case for 32 bit integer. m is the radix. When decreasing radix, increase number of characters (variable i). When increasing radix, decrease number of characters (better). In case of unsigned data type, i just becomes 16 + 1.



回答10:

i tried my own implementation of itoa(), it seem\'s work in binary, octal, decimal and 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;
}


回答11:

If you just want to print them:

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


回答12:

Reading the code of guys who do it for a living will get you a LONG WAY.

Check out how guys from MySQL did it. The source is VERY WELL COMMENTED and will teach you much more than hacked up solutions found all over the place.

MySQL\'s implementation of int2str

I provide the mentioned implementation here; the link is here for reference and should be used to read the full implementation.

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


回答13:

Where is the itoa function in Linux?

As itoa() is not standard in C, various versions with various function signatures exists.
char *itoa(int value, char *str, int base); is common in *nix.

Should it be missing from Linux or if code does not want to limit portability, code could make it own.

Below is a version that does not have trouble with INT_MIN and handles problem buffers: NULL or an insufficient buffer returns 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);
}

Below is a C99 or later version that handles any 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);
}

For a C89 and onward compliant code, replace inner loop with

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


回答14:

I have used _itoa(...) on RedHat 6 and GCC compiler. It works.



回答15:

glibc internal implementation

glibc 2.28 has an internal implementation:

  • https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/_itoa.c;h=3749ee97e320ceb62cbf76b6c93dd2beb38fe157;hb=3c03baca37fdcb52c3881e653ca392bba7a99c2b
  • https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/generic/_itoa.h;h=3749ee97e320ceb62cbf76b6c93dd2beb38fe157;hb=3c03baca37fdcb52c3881e653ca392bba7a99c2b

which is used in several places internally, but I could not find if it can be exposed or how.

At least that should be a robust implementation if you are willing to extract it.

This question asks how to roll your own: How to convert an int to string in C



回答16:

You can use this program instead of 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);
}


标签: c linux