Linux'ta itoa işlevi nerede?


140

itoa()bir sayıyı dizeye dönüştürmek için gerçekten kullanışlı bir işlevdir. Linux öyle görünmüyor itoa(), eşdeğer bir işlev var mı yoksa kullanmam gerekiyor sprintf(str, "%d", num)mu?


4
Kullanmamak için herhangi bir sebep var sprintf(str, "%d", num)mı? daha yavaş itoamı?
javapowered

1
@javapowered, birincisi, itoakeyfi taban dönüşümüne izin verir, printfbelirteçler yapmaz.
vladr

@javapowered sprintf () sinyal güvenli değil
lunesco

gcvt()Standart kütüphaneden kullanmamanız için herhangi bir neden var mı?
Subin Sebastian

Yanıtlar:


101

EDIT: Üzgünüm, bu makinenin kesinlikle standart olmayan libc, akademik amaçlı çeşitli standart dışı uygulamalara takılmış olduğunu hatırlamalıydım ;-)

Gibi itoa()birçok yararlı commenters belirtildiği gibi, gerçekten de standart dışı olduğunu, bu kullanmak en iyisidir sprintf(target_string,"%d",source_int)(Bu tampon taşmaları güvenli, çünkü daha iyisi) ya da snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). Biliyorum o kadar özlü veya havalı itoa()değil, ama en azından Bir Kez Yaz, Her Yerde Çalıştır (tm) ;-)

İşte eski (düzenlenmiş) cevap

Teknik olarak standardın bir parçası olmaması nedeniyle , varsayılanın diğer birçok platform gibi gcc libciçermediğini belirtmeniz doğrudur itoa(). Daha fazla bilgi için buraya bakın . Unutmayın

#include <stdlib.h>

Elbette bunu zaten biliyorsunuz, çünkü muhtemelen başka bir platformda kullandıktan sonra Linux'ta kullanmak istediniz itoa(), ancak ... kod (yukarıdaki bağlantıdan çalındı) şöyle görünecektir:

Misal

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

Çıktı:

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

Bu yardımcı olur umarım!


1
Hmmm, Debian'da derlediğimde bana "itoa'ya tanımsız referans" veriyor. Belki benim sistemimde bir sorun var.
Adam Pierce

Aynı şeyi Ubuntu 8.04'te de alıyorum. Itoa'ya stdio.h veya stdlib.h'de referans bulamıyorum (standardın bir parçası olmadığı için şaşırtıcı değil)
camh

doğruluk için düzenlenmiş, teşekkürler çocuklar! üzgünüm, her zaman bunun vanilya Linux kutusu olmadığını unutuyorum ;-)
Matt J

Ben arabellek boyutu argümanı dahil etmek cevap düzenledim; Her şeyin şimdi olması gerektiği gibi olduğuna inanıyorum, argümanların sırası ile ilgili bir sorun görmüyorum. Bir şey mi kaçırıyorum?
Matt J

Linux için çalışmıyor mu? soru / cevap sonucu nedir (Standart olmayan tüm linuxes gibi görünüyor?)

12

Çok çağırıyorsanız, "sadece snprintf kullanın" tavsiyesi sinir bozucu olabilir. İşte muhtemelen istediğiniz şey:

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
gibi yorum :)
James Antill

17
Sadece iş parçacığı için güvenli değil, hiç de güvenli değil: - void some_func (char * a, char * b); some_func (itoa (123), itoa (456)); İşlevin ne aldığını tahmin etmek ister misiniz?
jcoder

Ayrıca, constniteleyiciler işlev dönüş türlerinde hiçbir şey yapmaz - derleyici uyarılarını açarsanız bunu bilirsiniz :)
cat

3
@cat Ama burada const nitelikli dönüş türleri yok. const char *const için sabit olmayan bir işaretçi, bu çok mantıklı ve doğru.
Chortos-2

1
Chortos-2 ilginç @, sen, elbette, tamamen doğru - ben anlam içinde anlamsal farklılık fark etmedi constarasında const int f (void) { ...ve const int* f (void) { ...mantıklı bir derleyici ile denedim ettikten şimdi ama.
kedi

12

itoastandart C işlevi değildir. Kendinizinkini uygulayabilirsiniz. Bu ilk sayısında yayınlandı Kernighan ve Ritchie'nin Dili Programlama C sayfa 60., aşağıdaki uygulanmasını içermektedir ( "K & R2") Dil Programlama C ikinci sürümünü itoabu uygulamasıyla kitap notları sayfa 64., birkaç sorunu , en negatif sayıyı doğru işlememesi de dahil

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

reverseYukarıda kullanılan işlev iki sayfa önce uygulanır:

 #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

Düzenleme: Ben sadece std::to_stringaşağıdaki kendi işlevi için operasyonda özdeş hakkında öğrendim . C ++ 11'de tanıtıldı ve gcc'nin son sürümlerinde, c ++ 0x uzantılarını etkinleştirirseniz en az 4.5 kadar kullanılabilir.


Sadece itoagcc'de eksik olmakla kalmaz, aynı zamanda bir tamponu beslemeniz gerektiğinden kullanımı en kolay işlev değildir. Bir ifadede kullanılabilecek bir şeye ihtiyacım vardı, bu yüzden bu ile geldim:

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

Normalde bunun snprintfyerine kullanılması daha güvenli olur , sprintfancak tampon taşması için bağışıklık sağlayacak şekilde dikkatlice boyutlandırılır.

Bir örneğe bakın: http://ideone.com/mKmZVE


12
Soru, std::vb.
İçermeyen

6

Matt J'in yazdığı gibi, var itoa, ama standart değil. Kullanırsanız kodunuz daha taşınabilir olacaktır snprintf.


4

Aşağıdaki işlev, verilen sayının dize temsilini korumak için yeterli bellek ayırır ve sonra dize temsilini standart sprintfyöntem kullanarak bu alana yazar .

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İhtiyaç duyulmadığında ayrılan belleği doldurmayı unutmayın :

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

NB snprintf n-1 baytını kopyaladığı için snprintf (buf, len + 1, "% ld", n) (sadece snprintf (buf, len, "% ld", n))


4
Bu sizin işlevi çağırmak için iyi bir fikir değil itoaama ortak uygulamaları ne o farklı davranışlar vermek itoaaslında var. Bu işlev bir Tamam fikir ama başka bir şey olarak adlandırın :) Ayrıca snprintfkayan nokta dize yerine tampon uzunluğunu hesaplamak için kullanmanızı öneririm ; kayan nokta köşe kasa yanlışlıklarına sahip olabilir. Ve calloc kullanmayın
MM

Önerileriniz için teşekkürler.
mmdemirbas

Bu, labsuzun bir tamsayı alacaksa kullanılmalıdır. Yoksa kesilebilir.
Schwern

snprintfsabit boyutlu bir tmp tampon içine char buf[64]uzunluğu almak istiyorum , mallocve sonra içine kopyalayın. Sen dışarı bir yarar elde değil callocüzerinde malloctüm bayt yazma beri. Çok kısa bir dizenin fazladan kopyalanması kayan nokta log10'u çağırmaktan daha az kötüdür. Bununla birlikte, verimli bir şeye (x86'da olduğu gibi bsr) güvenilir bir şekilde hizalanacak bir bit tarama fonksiyonunuz varsa, bir tamsayı log2 ile hızlı bir yaklaşım yararlı olabilir . (Alternatif: malloc64 baytlık bir arabellek ve daha reallocsonra son uzunluğu
Peter Cordes

3

Linux'ta itoa işlevi nerede?

Linux'ta böyle bir işlev yoktur. Bunun yerine bu kodu kullanıyorum.

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

Bu kodun soruyu nasıl yanıtladığını açıklamak için cevabınızı düzenlemelisiniz.
C.Helling

2

itoa () kendi uygulama denedim, ikili, sekizli, ondalık ve onaltılık iş gibi görünüyor

#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

arabelleğe doğrudan kopyalama: 64 bit tam sayı 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];
    }

Not: 32 bit makine için uzun ila uzun uzun değiştirin. 32 bit tamsayı durumunda int için uzun. m yarıçaptır. Yarıçapı azaltırken, karakter sayısını artırın (değişken i). Sayı tabanı artarken, karakter sayısını azaltın (daha iyi). İmzasız veri türü durumunda, sadece 16 + 1 olur.


1

İşte Archana'nın çözümünün çok gelişmiş bir versiyonu. 1-16 yarıçapları ve <= 0 sayıları için çalışır ve hafızayı hızlandırmamalıdır.

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

Sadece yazdırmak istiyorsanız:

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

Yaşamak için bunu yapanların kodunu okumak size UZUN BİR YOL kazandıracaktır.

MySQL'den gelenlerin bunu nasıl yaptığını kontrol edin. Kaynak ÇOK İYİ DEĞERLENDİRİLMİŞTİR ve her yerde bulunan saldırıya uğramış çözümlerden çok daha fazlasını öğretecektir.

MySQL'in int2str uygulaması

Bahsedilen uygulamayı burada sağlıyorum; bağlantı referans için burada ve tam uygulamayı okumak için kullanılmalıdır.

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
Potansiyel bir çözümün bağlantısı her zaman açığız, ancak lütfen bağlantınızın çevresine bağlam ekleyin, böylece diğer kullanıcılarınız bunun ne olduğunu ve neden orada olduğunu bilmeleri gerekir. Hedef siteye erişilemiyorsa veya kalıcı olarak çevrimdışı olursa, her zaman önemli bir bağlantının en alakalı kısmını belirtin. Harici bir siteye bağlantıdan çok daha fazla olmanın Neden ve nasıl bazı cevapların silinmesinin olası bir nedeni olduğunu dikkate alın. .
Tunaki

1
Peki, burada paylaştığınız pasajda bu kadar iyi olan nedir? Gelecekteki okuyucular nelere dikkat etmelidir?
Martijn Pieters

1

Linux'ta itoa işlevi nerede?

As itoa()C standart değil, çeşitli fonksiyon imzalarla çeşitli versiyonları bulunmaktadır.
char *itoa(int value, char *str, int base);* nix'te yaygındır.

Linux'ta eksikse veya kod taşınabilirliği sınırlamak istemiyorsa, kod kendi başına yapabilir.

Aşağıda, sorunu olmayan INT_MINve sorunlu arabellekleri işleyen bir sürüm bulunmaktadır : NULLveya yetersiz arabellek döner 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şağıda herhangi bir tabanı işleyen bir C99 veya sonraki bir sürüm bulunmaktadır [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 ve üstü uyumlu kodlar için iç halkayı

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




0

Snprintf ile değiştirme işlemi DEĞİLDİR!

Sadece 2, 8, 10, 16 bazlarını kapsar, itoa ise 2 ve 36 arasındaki bazlar için çalışır.

Ben temel 32 yerine bir yedek arıyor beri, sanırım kendi kodlamak zorunda kalacak!


-4

Bu programı sprintf yerine kullanabilirsiniz.

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
Bu kodda çok fazla hata var: 1) Aslında hex'i doğru dönüştürmüyor. 2) 0'ı hiç dönüştürmez. 3) Negatif sayılarla çalışmaz. 4) Arabellek taşması kontrolü yok. Kısa süre içinde bu kodun geliştirilmiş bir sürümünü yayınlayacağım.
Chris Desjardins
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.