Onde está a função itoa no Linux?

139

itoa()é uma função realmente útil para converter um número em uma string. Parece que o Linux não tem itoa(), existe uma função equivalente ou eu tenho que usar sprintf(str, "%d", num)?

Adam Pierce
fonte
4
alguma razão para não usar sprintf(str, "%d", num)? é muito mais lento que itoa?
Javapowered
1
O @javapowered, por um lado, itoapermite a conversão arbitrária de bases, os printfespecificadores não.
vladr
@javapowered sprintf () não é sinal seguro
lunesco
Alguma razão para não usar gcvt()da biblioteca padrão?
Subin Sebastian

Respostas:

100

EDIT: Desculpe, eu deveria ter lembrado que esta máquina é decididamente não padrão, tendo conectado várias libcimplementações não padrão para fins acadêmicos ;-)

Como, de itoa()fato, não é padrão, como mencionado por vários comentadores úteis, é melhor usar sprintf(target_string,"%d",source_int)ou (melhor ainda, porque é seguro contra estouros de buffer) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). Eu sei que não é tão conciso ou legal quanto itoa(), mas pelo menos você pode Escrever Uma Vez, Executar em Todo Lugar (tm) ;-)

Aqui está a resposta antiga (editada)

Você está certo ao afirmar que o padrão gcc libcnão inclui itoa(), como várias outras plataformas, devido ao fato de não ser tecnicamente parte do padrão. Veja aqui um pouco mais de informação. Observe que você precisa

#include <stdlib.h>

Claro que você já sabe disso, porque queria usar itoa() no Linux depois de usá-lo em outra plataforma, mas ... o código (roubado do link acima) teria a seguinte aparência:

Exemplo

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

Resultado:

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

Espero que isto ajude!

Matt J
fonte
1
Hmmm, compilar isso no Debian me dá "referência indefinida a` itoa '". Talvez algo esteja errado com o meu sistema.
266 Adam Pierce
Eu recebo o mesmo no Ubuntu 8.04. Posso encontrar nenhuma referência a itoa em stdio.h ou stdlib.h quer (não surpreendente, uma vez que não é parte do padrão)
CAMH
editado para correção, obrigado pessoal! desculpe, eu sempre esqueço que esta não é uma caixa de baunilha Linux ;-)
Matt J
Eu editei a resposta para incluir o argumento de tamanho do buffer; Acredito que tudo está como deveria ser agora, não vejo problema com a ordem dos argumentos em si. Estou esquecendo de algo?
Matt J
Não funciona para Linux? o que é o resultado da pergunta / resposta (Non padrão parece ser todos Linuxes?)
12

Se você está chamando muito, o conselho de "apenas use snprintf" pode ser irritante. Então aqui está o que você provavelmente quer:

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); }
James Antill
fonte
8
como o comentário disse :)
James Antill
17
Não é apenas seguro não-thread, não é muito seguro: - void some_func (char * a, char * b); algum_func (itoa (123), itoa (456)); Importa-se de adivinhar o que a função recebe?
jcoder
Além disso, constqualificadores não fazer nada sobre os tipos de retorno de função - você saberia isso se transformou em avisos do compilador :)
gato
3
@cat Mas não existem tipos de retorno com qualificação const aqui. const char *é um ponteiro não const para const, o que faz muito sentido e está correto.
Chortos-2
1
@ Chortos-2 Isso é interessante, é claro que você está completamente correto - eu não percebi a diferença semântica no significado de constentre const int f (void) { ...e const int* f (void) { ..., mas agora, depois de tentar com um compilador, faz sentido.
Cat #
11

itoanão é uma função C padrão. Você pode implementar o seu próprio. Ele apareceu na primeira edição da linguagem de programação C de Kernighan e Ritchie , na página 60. A segunda edição da linguagem de programação C ("K & R2") contém a seguinte implementação de , na página 64. O livro observa vários problemas com essa implementação , incluindo o fato de que ele não lida corretamente com o número mais negativoitoa

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

A função reverseusada acima é implementada duas páginas anteriormente:

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

Edit: Acabei de descobrir sobre o std::to_stringque é idêntico em operação à minha própria função abaixo. Foi introduzido no C ++ 11 e está disponível nas versões recentes do gcc, pelo menos a partir da versão 4.5, se você ativar as extensões c ++ 0x.


Falta não apenas itoano gcc, como também não é a função mais útil, pois você precisa alimentar um buffer. Eu precisava de algo que pudesse ser usado em uma expressão, então eu vim com isso:

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

Normalmente, seria mais seguro usá-lo em snprintfvez de, sprintfmas o buffer é cuidadosamente dimensionado para ficar imune a transbordamentos.

Veja um exemplo: http://ideone.com/mKmZVE

Mark Ransom
fonte
12
A pergunta parece ser sobre C, que não tem nada std::etc.
glglgl 31/01
6

Como Matt J escreveu, existe itoa, mas não é padrão. Seu código será mais portátil se você usar snprintf.

Mark Karpov
fonte
4

A função a seguir aloca memória suficiente para manter a representação em seqüência do número especificado e, em seguida, grava a representação em seqüência nessa área usando o sprintfmétodo padrão .

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ão se esqueça de freeaumentar a memória alocada quando fora de necessidade:

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

NB Como o snprintf copia n-1 bytes, precisamos chamar snprintf (buf, len + 1, "% ld", n) (não apenas snprintf (buf, len, "% ld", n))

mmdemirbas
fonte
4
Não é uma boa idéia chamar sua função, itoamas atribuir um comportamento diferente ao que as implementações comuns itoarealmente têm. Essa função é uma boa idéia, mas chame-a de outra coisa :) Eu também sugeriria usar snprintfpara calcular o comprimento do buffer em vez da string de ponto flutuante; ponto flutuante pode ter imprecisões na caixa de canto. E não lance calloc
MM
Obrigado por sugestões.
mmdemirbas
Isso deve ser usado labsse for necessário um número inteiro longo. Caso contrário, pode truncar.
Schwern
snprintfem um buffer tmp de tamanho fixo, como char buf[64]para obter o comprimento malloce copie para ele. Você não está recebendo qualquer benefício para fora do callocmais malloc, uma vez que você escreve todos os bytes. A cópia extra de uma sequência muito curta é menos ruim do que ter que chamar log de ponto flutuante10. Uma aproximação rápida com um log2 inteiro pode ser útil, no entanto, se você tiver uma função de varredura de bits que se alinha de maneira confiável a algo eficiente (como bsrno x86). (Alternativa: mallocum buffer de 64 bytes e, em seguida, reallocdepois que você sabe o comprimento final.)
Peter Cordes
3

Onde está a função itoa no Linux?

Não existe essa função no Linux. Eu uso esse código em seu lugar.

/*
=============
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;
}
rick-rick-rick
fonte
Você deve editar sua resposta para explicar como esse código responde à pergunta.
C. Helling
2

Eu tentei minha própria implementação de itoa (), parece que o trabalho em binário, octal, decimal e 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;
}
waaagh
fonte
1

cópia direta para o buffer: número inteiro de 64 bits 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];
    }

nota: mude muito para muito tempo na máquina de 32 bits. longo para int no caso de um inteiro de 32 bits. m é a raiz. Ao diminuir o raio, aumente o número de caracteres (variável i). Ao aumentar o raio, diminua o número de caracteres (melhor). No caso de um tipo de dados não assinado, eu apenas me tornarei 16 + 1.

o sudhakar
fonte
1

Aqui está uma versão muito melhorada da solução do Archana. Funciona para qualquer raiz 1-16 e números <= 0, e não deve desperdiçar memória.

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

Se você quiser apenas imprimi-los:

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");
} 
Andres Romero
fonte
1

Lendo o código de pessoas que fazem isso da vida, você terá um LONGO CAMINHO.

Veja como os caras do MySQL fizeram isso. A fonte é MUITO BEM COMENTADA e ensinará muito mais do que soluções hackeadas encontradas em todo o lugar.

Implementação do MySQL do int2str

Eu forneço a implementação mencionada aqui; o link está aqui para referência e deve ser usado para ler a implementação completa.

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;
}
Vlatko Šurlan
fonte
1
Um link para uma solução em potencial é sempre bem-vindo, mas adicione contexto ao link para que seus colegas usuários tenham uma idéia do que é e por que está lá. Sempre cite a parte mais relevante de um link importante, caso o site de destino esteja inacessível ou fique permanentemente offline. Leve em conta que ser pouco mais que um link para um site externo é uma possível razão para Por que e como algumas respostas são excluídas? .
Tunaki
1
Então, o que há de tão bom no snippet que você postou aqui? O que os futuros leitores devem procurar?
Martijn Pieters
1

Onde está a função itoa no Linux?

Como itoa()não é padrão em C, existem várias versões com várias assinaturas de funções.
char *itoa(int value, char *str, int base);é comum em * nix.

Caso esteja faltando no Linux ou se o código não quiser limitar a portabilidade, o código poderá torná-lo próprio.

Abaixo está uma versão que não apresenta problemas INT_MINe lida com buffers com problemas: NULLou retorna um buffer insuficiente 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);
}

Abaixo está uma versão C99 ou posterior que lida com qualquer 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);
}

Para um código compatível com C89 e seguintes, substitua o loop interno por

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

implementação interna glibc

O glibc 2.28 possui uma implementação interna:

que é usado em vários lugares internamente, mas não consegui descobrir se pode ser exposto ou como.

Pelo menos essa deve ser uma implementação robusta, se você deseja extraí-la.

Esta pergunta pergunta como fazer o seu próprio: Como converter um int para string em C?

Ciro Santilli adicionou uma nova foto
fonte
1

Eu preferiria isso: https://github.com/wsq003/itoa_for_linux

Deve ser o itoa () mais rápido de todos os tempos. Usamos itoa () em vez de sprintf () por motivos de desempenho, portanto, uma itoa () mais rápida com recursos limitados é razoável e vale a pena.

Shaoquan
fonte
0

Eu usei _itoa (...) no compilador RedHat 6 e GCC. Funciona.

m_pGladiator
fonte
0

A substituição pelo snprintf NÃO está completa!

Abrange apenas bases: 2, 8, 10, 16, enquanto itoa funciona para bases entre 2 e 36.

Desde que eu estava procurando um substituto para a base 32, acho que vou ter que codificar o meu!

Zakhar
fonte
-4

Você pode usar este programa em vez do 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);
}
Archana Chatterjee
fonte
4
Existem muitos erros neste código: 1) Na verdade, não converte hexadecimal corretamente. 2) Não converte 0. 3) Não funciona com números negativos. 4) Nenhuma verificação de saturação de buffer. Em breve, publicarei uma versão aprimorada desse código.
precisa