代码之家  ›  专栏  ›  技术社区  ›  Adam Pierce

Linux中的itoa函数在哪里?

  •  168
  • Adam Pierce  · 技术社区  · 16 年前

    itoa() 是一个非常方便的函数,可以将数字转换为字符串。Linux似乎没有 itoa() ,是否有等效功能或我必须使用 sprintf(str, "%d", num) ?

    18 回复  |  直到 11 年前
        1
  •  116
  •   Matt J Jørgen Fogh    15 年前

    编辑:对不起,我应该记得这台机器肯定是非标准的,插了各种非标准的 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() 与其他几个平台一样,由于它在技术上不是标准的一部分。看见 here 了解更多信息。请注意,你必须

    #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
    
        2
  •  23
  •   Keith Thompson    9 年前

    itoa 不是标准的C函数。你可以实施你自己的。它出现在第一版 克尼汉 里奇的 C程序设计语言 ,见第60页。《C编程语言》(“K&R2”)的第二版包含以下实现 itoa ,见第64页。这本书指出了这种实现的几个问题,包括 它不能正确处理最负数

     /* 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;
         }
    }  
    
        3
  •  12
  •   James Antill    16 年前

    如果你经常称之为snprintf,那么“只使用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); }
    
        4
  •  9
  •   Mark Ransom    12 年前

    编辑: 我刚刚得知 std::to_string 其操作与下面我自己的功能相同。它是在C++11中引入的,在最新版本的gcc中可用,如果启用C++0x扩展,至少早在4.5版本就可以使用。


    不仅是 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

        5
  •  7
  •   Mark Karpov sheikh_anton    10 年前

    正如Matt J所写 itoa ,但这不是标准。如果你使用 snprintf .

        6
  •  5
  •   mmdemirbas    9 年前

    以下函数分配刚好足够的内存来保持给定数字的字符串表示,然后使用标准将字符串表示写入此区域 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);
    

    注意:由于snprintf复制N-1个字节,我们必须调用snprintf(buf,len+1,“%ld”,N)(而不仅仅是snprintf

        7
  •  4
  •   Martijn Pieters    9 年前

    阅读那些以此为生的人的代码会让你走得很远。

    看看MySQL的人是怎么做到的。这个源代码非常受欢迎,它将教你更多的东西,而不是到处都能找到的黑客解决方案。

    MySQL's implementation of 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;
    }
    
        8
  •  4
  •   rick-rick-rick    7 年前

    Linux中的itoa函数在哪里?

    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;
    }
    
        9
  •  3
  •   waaagh    12 年前

    我尝试了自己的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;
    }
    
        10
  •  2
  •   the sudhakar    12 年前

    直接复制到缓冲区:64位整数itoa十六进制:

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

    注意:对于32位机器,将long改为long long。在32位整数的情况下,long转换为int。m是基数。减小基数时,增加字符数(变量i)。增加基数时,减少字符数(更好)。在无符号数据类型的情况下,i只变为16+1。

        11
  •  2
  •   Chris Desjardins    12 年前

    这是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;
    }
    
        12
  •  2
  •   Andres Romero    11 年前

    Linux中的itoa函数在哪里?

    itoa() 在C中不是标准的,存在具有各种函数签名的各种版本。
    char *itoa(int value, char *str, int base); 在*nix中很常见。

    如果Linux中缺少它,或者代码不想限制可移植性,代码可以自己创建它。

    下面是一个没有问题的版本 INT_MIN 并处理问题缓冲区: 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);
    
        13
  •  2
  •   chux    7 年前

    glibc内部实现

    glibc 2.28有一个内部实现:

    它在内部的几个地方都有使用,但我找不到它是否可以暴露或如何暴露。

    如果你愿意提取它,至少这应该是一个强大的实现。

    这个问题问你如何滚动自己的: How to convert an int to string in C?

        14
  •  2
  •   Ciro Santilli OurBigBook.com    6 年前

    如果你只想打印它们:

    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");
    } 
    
        15
  •  2
  •   Danger Saints    5 年前

    替换为snprintf的操作尚未完成!

    它只涵盖2、8、10、16个碱基,而itoa适用于2到36之间的碱基。

    既然我在寻找32进制的替代品,我想我必须自己编写代码了!

        16
  •  1
  •   Zakhar    6 年前

    我更喜欢这样: https://github.com/wsq003/itoa_for_linux

    这应该是有史以来最快的。出于性能原因,我们使用itoa()而不是sprintf(),因此功能有限的最快itoa(()是合理且值得的。

        17
  •  0
  •   m_pGladiator    16 年前

    我在RedHat 6和GCC编译器上使用了_itoa(…)。它奏效了。

        18
  •  -5
  •   bstpierre Edgar Aviles    12 年前

    您可以使用此程序代替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);
    }