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)?
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 usaritoa() no Linux depois de usá-lo em outra plataforma, mas ... o código (roubado do link acima) teria a seguinte aparência:
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:
constchar*my_itoa_buf(char*buf,size_t len,int num){staticchar 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;}constchar*my_itoa(int num){return my_itoa_buf(NULL,0, num);}
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;}}
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:
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:
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 (unsignedlonglong 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((longlong) value <0){
value =-value;
sign =true;}}*--dest ='\0';switch(radix){case16:while(value){*--dest ='0'+(value &0xF);if(*dest >'9')*dest +='A'-'9'-1;
value >>=4;}break;case10:while(value){*--dest ='0'+(value %10);
value /=10;}break;case8:while(value){*--dest ='0'+(value &7);
value >>=3;}break;case2:while(value){*--dest ='0'+(value &1);
value >>=1;}break;default:// The slow version, but universalwhile(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;}
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)return0;
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.
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(longint val,char*dst,int radix,int upcase){char buffer[65];char*p;longint new_val;char*dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower;
ulong uval=(ulong) val;if(radix <0){if(radix <-36|| radix >-2)returnNullS;if(val <0){*dst++='-';/* Avoid integer overflow in (-val) for LLONG_MIN (BUG#31799). */
uval =(ulong)0- uval;}
radix =-radix;}elseif(radix >36|| radix <2)returnNullS;/*
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;}
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 valueint 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 stringsize_t src_size =(size_t)(&buf[sizeof buf]- p);if(src_size > dest_size){// Not enough roomreturn 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 stringsize_t src_size =(size_t)(&buf[sizeof buf]- p);if(src_size > dest_size){// Not enough roomreturn 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);
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.
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.
sprintf(str, "%d", num)
? é muito mais lento queitoa
?itoa
permite a conversão arbitrária de bases, osprintf
especificadores não.gcvt()
da biblioteca padrão?Respostas:
EDIT: Desculpe, eu deveria ter lembrado que esta máquina é decididamente não padrão, tendo conectado várias
libc
implementaçõ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 usarsprintf(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 quantoitoa()
, 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 libc
não incluiitoa()
, 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ê precisaClaro 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
Resultado:
Espero que isto ajude!
fonte
Se você está chamando muito, o conselho de "apenas use snprintf" pode ser irritante. Então aqui está o que você provavelmente quer:
fonte
const
qualificadores não fazer nada sobre os tipos de retorno de função - você saberia isso se transformou em avisos do compilador :)const char *
é um ponteiro não const para const, o que faz muito sentido e está correto.const
entreconst int f (void) { ...
econst int* f (void) { ...
, mas agora, depois de tentar com um compilador, faz sentido.itoa
nã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
A função
reverse
usada acima é implementada duas páginas anteriormente:fonte
Edit: Acabei de descobrir sobre o
std::to_string
que é 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
itoa
no 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:Normalmente, seria mais seguro usá-lo em
snprintf
vez de,sprintf
mas o buffer é cuidadosamente dimensionado para ficar imune a transbordamentos.Veja um exemplo: http://ideone.com/mKmZVE
fonte
std::
etc.Como Matt J escreveu, existe
itoa
, mas não é padrão. Seu código será mais portátil se você usarsnprintf
.fonte
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
sprintf
método padrão .Não se esqueça de
free
aumentar a memória alocada quando fora de necessidade:NB Como o snprintf copia n-1 bytes, precisamos chamar snprintf (buf, len + 1, "% ld", n) (não apenas snprintf (buf, len, "% ld", n))
fonte
itoa
mas atribuir um comportamento diferente ao que as implementações comunsitoa
realmente têm. Essa função é uma boa idéia, mas chame-a de outra coisa :) Eu também sugeriria usarsnprintf
para 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 calloclabs
se for necessário um número inteiro longo. Caso contrário, pode truncar.snprintf
em um buffer tmp de tamanho fixo, comochar buf[64]
para obter o comprimentomalloc
e copie para ele. Você não está recebendo qualquer benefício para fora docalloc
maismalloc
, 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 (comobsr
no x86). (Alternativa:malloc
um buffer de 64 bytes e, em seguida,realloc
depois que você sabe o comprimento final.)Não existe essa função no Linux. Eu uso esse código em seu lugar.
fonte
Eu tentei minha própria implementação de itoa (), parece que o trabalho em binário, octal, decimal e hex
fonte
cópia direta para o buffer: número inteiro de 64 bits itoa hex:
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.
fonte
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.
fonte
Se você quiser apenas imprimi-los:
fonte
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.
fonte
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_MIN
e lida com buffers com problemas:NULL
ou retorna um buffer insuficienteNULL
.Abaixo está uma versão C99 ou posterior que lida com qualquer base [2 ... 36]
Para um código compatível com C89 e seguintes, substitua o loop interno por
fonte
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?
fonte
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.
fonte
Eu usei _itoa (...) no compilador RedHat 6 e GCC. Funciona.
fonte
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!
fonte
Você pode usar este programa em vez do sprintf.
fonte