web-dev-qa-db-fra.com

Où se trouve la fonction itoa sous Linux?

itoa() est une fonction très pratique pour convertir un nombre en chaîne. Linux ne semble pas avoir itoa(), existe-t-il une fonction équivalente ou dois-je utiliser sprintf(str, "%d", num)?

124
Adam Pierce

EDIT: Désolé, j'aurais dû me rappeler que cette machine est résolument non standard, après avoir branché diverses implémentations libc non standard à des fins académiques ;-)

Comme itoa() est en effet non standard, comme mentionné par plusieurs commentateurs utiles, il est préférable d’utiliser sprintf(target_string,"%d",source_int) ou (mieux encore, car il est à l’abri des débordements de mémoire tampon) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). Je sais que ce n'est pas aussi concis ni aussi cool que itoa(), mais au moins, vous pouvez écrire une fois, exécuter tout le monde (tm) ;-)

Voici l'ancienne réponse (modifiée)

Vous avez raison de dire que le gcc libc par défaut n'inclut pas itoa(), à l'instar de plusieurs autres plates-formes, car techniquement, il ne fait pas partie du standard. Voir ici pour un peu plus d’informations. Notez que vous devez 

#include <stdlib.h>

Bien sûr, vous le savez déjà, car vous vouliez utiliser utiliseritoa() sous Linux après l'avoir utilisé sur une autre plate-forme, mais ... le code (volé à partir du lien ci-dessus) ressemblerait à ceci:

Exemple

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

Sortie:

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

J'espère que cela t'aides!

87
Matt J

Si vous l'appelez souvent, le conseil "n'utilisez que snprintf" peut être ennuyeux. Alors, voici ce que vous voulez probablement:

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); }
12
James Antill

itoa n'est pas une fonction C standard. Vous pouvez implémenter le vôtre. Il est apparu dans la première édition de Kernighan et Ritchie'sLe langage de programmation C, à la page 60. La deuxième édition du langage de programmation C ("K & R2") contient les suite à l’implémentation de itoa, à la page 64. Le livre note plusieurs problèmes liés à cette implémentation, notamment le fait que il ne gère pas correctement le nombre le plus négatif 

 /* 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 fonction reverse utilisée ci-dessus est implémentée deux pages plus tôt:

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

Edit: Je viens de découvrir std::to_string dont le fonctionnement est identique à celui de ma fonction ci-dessous. Il a été introduit en C++ 11 et est disponible dans les versions récentes de gcc, au moins dès la version 4.5 si vous activez les extensions c ++ 0x .


Non seulement itoa manque dans gcc, mais ce n’est pas la fonction la plus pratique à utiliser car vous devez l’alimenter en mémoire tampon. J'avais besoin de quelque chose qui puisse être utilisé dans une expression alors je suis arrivé avec ceci:

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

Normalement, il serait plus prudent d’utiliser snprintf au lieu de sprintf, mais la taille du tampon est soigneusement dimensionnée pour ne pas être dépassée.

Voir un exemple: http://ideone.com/mKmZVE

7
Mark Ransom

Comme l'a écrit Matt J, il existe itoa, mais ce n'est pas standard. Votre code sera plus portable si vous utilisez snprintf.

6
Mike

La fonction suivante alloue juste assez de mémoire pour conserver la représentation sous forme de chaîne du nombre donné, puis écrit la représentation sous forme de chaîne dans cette zone à l'aide de la méthode standard 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;
}

N'oubliez pas de free augmenter la mémoire allouée en cas de besoin:

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

N.B. Comme snprintf copie n-1 octets, nous devons appeler snprintf (buf, len + 1, "% ld", n) (pas seulement snprintf (buf, len, "% ld", n))

4
mmdemirbas

Où se trouve la fonction itoa sous Linux?

Une telle fonction n'existe pas sous Linux. J'utilise ce code à la place.

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

Voici une version nettement améliorée de la solution d'Archana. Cela fonctionne pour tous les radix 1-16, et les nombres <= 0, et cela ne devrait pas surcharger la mémoire. 

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;
}
2
Chris Desjardins

Lire le code des gars qui le font pour gagner leur vie vous procurera un long chemin.

Découvrez comment les gars de MySQL l'ont fait. La source est TRÈS BIEN COMMENCÉE et vous en apprendra beaucoup plus que des solutions bidouillées trouvées partout.

Implémentation de int2str par MySQL

Je fournis la mise en œuvre mentionnée ici; le lien est ici pour référence et doit être utilisé pour lire la mise en œuvre complète.

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
Vlatko Šurlan

Si vous voulez juste les imprimer:

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
Andres Romero

Où se trouve la fonction itoa sous Linux?

Comme itoa() n'est pas standard en C, il existe différentes versions avec différentes signatures de fonctions.
char *itoa(int value, char *str, int base); est commun dans * nix.

Si Linux le manquait ou si le code ne veut pas limiter la portabilité, le code pourrait le rendre propre.

Ci-dessous, une version qui n’a pas de problème avec INT_MIN et qui gère les tampons posant problème: NULL ou un tampon insuffisant renvoie 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);
}

Ci-dessous, une version C99 ou ultérieure qui gère n’importe quelle 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);
}

Pour un code conforme C89 et ultérieur, remplacez la boucle interne par

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

copie directe dans le tampon: entier 64 bits

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

remarque: changez long à long long pour une machine 32 bits. long to int au cas où l'entier sur 32 bits. m est la base. Lorsque vous réduisez la base, augmentez le nombre de caractères (variable i). Lorsque vous augmentez la base, diminuez le nombre de caractères (mieux). En cas de type de données non signé, je deviens simplement 16 + 1.

1
the sudhakar

j'ai essayé ma propre implémentation de itoa (), il semble que le travail en binaire, octal, décimal et 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;
}
1
waaagh

Le remplacement par snprintf n'est pas complet!

Il ne couvre que les bases: 2, 8, 10, 16, alors que itoa fonctionne pour les bases entre 2 et 36.

Depuis que je cherchais un remplaçant pour la base 32, je suppose que je devrai me coder!

0
Zakhar

Je préférerais ceci: https://github.com/wsq003/itoa_for_linux

Ce devrait être le plus rapide itoa () de tous les temps. Nous utilisons itoa () au lieu de sprintf () pour des raisons de performances. Un itoa () le plus rapide avec des fonctionnalités limitées est raisonnable et vaut la peine.

0
Shaoquan

J'ai utilisé _itoa (...) sur RedHat 6 et le compilateur GCC. Ça marche.

0
m_pGladiator