itoa()to bardzo przydatna funkcja do konwersji liczby na łańcuch. Wydaje się itoa(), że Linux nie ma , czy istnieje równoważna funkcja, czy muszę jej użyć sprintf(str, "%d", num)?
jakiś powód, aby nie używać sprintf(str, "%d", num)? czy jest dużo wolniejszy niż itoa?
javapowered
1
@javapowered, na przykład, itoapozwala na dowolną konwersję bazy, printfspecyfikatory nie.
vladr
@javapowered sprintf () nie jest bezpiecznym sygnałem
lunesco
Czy jest jakiś powód, aby nie używać gcvt()biblioteki standardowej?
Subin Sebastian
Odpowiedzi:
100
EDYCJA: Przepraszam, powinienem był pamiętać, że ta maszyna jest zdecydowanie niestandardowa, po podłączeniu różnych niestandardowych libcimplementacji do celów naukowych ;-)
Ponieważ itoa()jest to rzeczywiście niestandardowe, o czym wspomniało kilku pomocnych komentatorów, najlepiej jest użyć sprintf(target_string,"%d",source_int)lub (jeszcze lepiej, ponieważ jest bezpieczny przed przepełnieniem bufora) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). Wiem, że to nie jest tak zwięzłe ani fajne, jak itoa(), ale przynajmniej możesz napisać raz, biegać wszędzie (tm) ;-)
Oto stara (zredagowana) odpowiedź
Masz rację twierdząc, że domyślna gcc libcwersja nie obejmuje itoa(), jak kilka innych platform, ponieważ technicznie nie jest częścią standardu. Zobacz tutaj, aby uzyskać więcej informacji. Pamiętaj, że musisz
#include<stdlib.h>
Oczywiście już to wiesz, ponieważ chciałeś używaćitoa() na Linuksie po przypuszczalnym użyciu go na innej platformie, ale ... kod (skradziony z powyższego linku) wyglądałby tak:
Hmmm, kompilacja tego na Debianie daje mi „niezdefiniowane odniesienie do„ itoa ””. Może coś jest nie tak z moim systemem.
Adam Pierce
To samo mam na Ubuntu 8.04. Nie mogę znaleźć żadnego odniesienia do itoa w stdio.h ani stdlib.h (nie jest to zaskakujące, ponieważ nie jest częścią standardu)
camh
edytowane pod kątem poprawności, dzięki chłopaki! przepraszam, zawsze zapominam, że to nie jest zwykła skrzynka z Linuksem ;-)
Matt J,
Edytowałem odpowiedź, aby uwzględnić argument rozmiaru bufora; Uważam, że teraz wszystko jest tak, jak powinno, nie widzę problemu z kolejnością argumentów jako taką. Czy coś mi brakuje?
Matt J,
To nie działa na Linuksie? jaki jest wynik pytania / odpowiedzi (wydaje się, że niestandardowe są wszystkie systemy Linux?)
12
Jeśli często to nazywasz, porada „po prostu użyj snprintf” może być denerwująca. Oto, czego prawdopodobnie chcesz:
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);}
To nie tylko nie jest bezpieczne dla wątków, jest w ogóle niezbyt bezpieczne: - void some_func (char * a, char * b); some_func (itoa (123), itoa (456)); Chcesz zgadnąć, co otrzymuje funkcja?
jcoder
Ponadto constkwalifikatory nie wpływają na typy zwracane przez funkcję - wiedziałbyś o tym, gdybyś włączył ostrzeżenia kompilatora :)
cat
3
@cat Ale nie ma tutaj żadnych zwrotów kwalifikowanych jako const. const char *jest wskaźnikiem niebędącym stałym do const, co ma dużo sensu i jest poprawne.
Chortos-2
1
@ Chortos-2 To interesujące, oczywiście masz całkowitą rację - nie zdawałem sobie sprawy z semantycznej różnicy w znaczeniu constmiędzy const int f (void) { ...i const int* f (void) { ..., ale teraz, gdy wypróbowałem to z kompilatorem, ma to sens.
kot
11
itoanie jest standardową funkcją C. Możesz wdrożyć własne. Pojawił się w pierwszym wydaniu języka programowania C Kernighana i Ritchiego , na stronie 60. Drugie wydanie języka programowania C („K & R2”) zawiera następującą implementację , na stronie 64. Książka zwraca uwagę na kilka kwestii związanych z tą implementacją , w tym fakt, że nie obsługuje poprawnie większości liczb ujemnychitoa
/* 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);}
Funkcja reverseużyta powyżej została zaimplementowana dwie strony wcześniej:
#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;}}
Edycja: właśnie dowiedziałem się, std::to_stringktóra jest identyczna w działaniu jak moja własna funkcja poniżej. Został wprowadzony w C ++ 11 i jest dostępny w najnowszych wersjach gcc, przynajmniej od 4.5, jeśli włączysz rozszerzenia c ++ 0x.
Nie tylko itoabrakuje go w gcc, ale nie jest to najłatwiejsza funkcja w użyciu, ponieważ musisz podać jej bufor. Potrzebowałem czegoś, co można by użyć w wyrażeniu, więc wymyśliłem to:
Następująca funkcja przydziela wystarczającą ilość pamięci, aby zachować ciąg reprezentujący podaną liczbę, a następnie zapisuje reprezentację ciągu w tym obszarze przy użyciu standardowej sprintfmetody.
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;}
Nie zapomnij o freezwiększeniu przydzielonej pamięci, gdy jej nie potrzebujesz:
Nie jest dobrym pomysłem wywoływanie funkcji, itoaale nadanie jej innego zachowania niż to, co itoafaktycznie mają powszechne implementacje . Ta funkcja jest dobrym pomysłem, ale nazwij ją inaczej :) Sugerowałbym również użycie snprintfdo obliczenia długości bufora zamiast łańcucha zmiennoprzecinkowego; zmiennoprzecinkowe mogą mieć niedokładności wielkości liter narożnych. I nie rzucaj calloc
MM
Dzięki za sugestie.
mmdemirbas
Powinien być użyty, labsjeśli zajmie to długą liczbę całkowitą. W przeciwnym razie może zostać obcięty.
Schwern
snprintfdo bufora tmp o stałym rozmiarze, na przykład w char buf[64]celu uzyskania długości, a następnie mallocskopiuj do niego. Nie odniesiesz żadnej korzyści z callocover malloc, ponieważ piszesz wszystkie bajty. Dodatkowe kopiowanie bardzo krótkiego łańcucha jest mniej złe niż wywołanie log10 zmiennoprzecinkowego. Szybkie przybliżenie za pomocą liczby całkowitej log2 może być jednak przydatne, jeśli masz funkcję skanowania bitów, która niezawodnie będzie wbudowana w coś wydajnego (jak bsrna x86). (Alternatywnie: malloc64-bajtowy bufor, a następnie reallocpo znaniu ostatecznej długości.)
Peter Cordes,
3
Gdzie jest funkcja itoa w systemie Linux?
W Linuksie nie ma takiej funkcji. Zamiast tego używam tego kodu.
/*
=============
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;}
bezpośrednia kopia do bufora: 64-bitowa liczba całkowita 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];}
Uwaga: zmień długi na długi długi dla maszyny 32-bitowej. long to int w przypadku 32-bitowej liczby całkowitej. m jest podstawą. Zmniejszając podstawę, zwiększ liczbę znaków (zmienna i). Zwiększając podstawę, zmniejsz liczbę znaków (lepiej). W przypadku typu danych bez znaku, i staje się po prostu 16 + 1.
Czytanie kodu facetów, którzy zajmują się tym na życie, da ci DŁUGIE SPOSOBY.
Sprawdź, jak zrobili to faceci z MySQL. Źródło jest BARDZO DOBRZE KOMENTARZE i nauczy Cię znacznie więcej niż zhakowanych rozwiązań znalezionych w każdym miejscu.
Podaję tutaj wspomnianą implementację; link jest tutaj w celach informacyjnych i powinien być używany do czytania pełnej implementacji.
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;}
Link do potencjalnego rozwiązania jest zawsze mile widziany, ale dodaj kontekst do niego, aby inni użytkownicy mieli pojęcie, co to jest i dlaczego się tam znajduje. Zawsze cytuj najbardziej odpowiednią część ważnego linku, na wypadek gdyby strona docelowa była nieosiągalna lub została trwale wyłączona. Weź pod uwagę, że fakt, że niewiele więcej niż łącze do zewnętrznej witryny jest możliwym powodem, dlaczego i jak są usuwane niektóre odpowiedzi? .
Tunaki
1
Więc co jest takiego dobrego w opublikowanym tutaj fragmencie? Na co powinni zwrócić uwagę przyszli czytelnicy?
Martijn Pieters
1
Gdzie jest funkcja itoa w systemie Linux?
Ponieważ itoa()nie jest to standardem w C, istnieją różne wersje z różnymi podpisami funkcji. char *itoa(int value, char *str, int base);jest powszechne w * nix.
Jeśli brakuje go w Linuksie lub jeśli kod nie chce ograniczać przenośności, kod może uczynić go własnym.
Poniżej znajduje się wersja, która nie ma problemów z problemami z INT_MINbuforami i nie obsługuje buforów: NULLlub zwraca niewystarczający bufor 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);}
Poniżej znajduje się wersja C99 lub nowsza, która obsługuje dowolną podstawę [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);}
W przypadku kodu zgodnego ze standardem C89 i nowszym zamień pętlę wewnętrzną na
div_t qr;do{
qr = div(neg_num, base);*--p ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
neg_num = qr.quot;}while(neg_num);
Powinna to być najszybsza itoa () w historii. Używamy itoa () zamiast sprintf () ze względu na wydajność, więc najszybsza itoa () z ograniczonymi funkcjami jest rozsądna i warta zachodu.
W tym kodzie jest tak wiele błędów: 1) W rzeczywistości nie konwertuje poprawnie szesnastkowo. 2) W ogóle nie konwertuje 0. 3) Nie działa z liczbami ujemnymi. 4) Brak sprawdzania przepełnienia bufora. Wkrótce opublikuję ulepszoną wersję tego kodu.
sprintf(str, "%d", num)
? czy jest dużo wolniejszy niżitoa
?itoa
pozwala na dowolną konwersję bazy,printf
specyfikatory nie.gcvt()
biblioteki standardowej?Odpowiedzi:
EDYCJA: Przepraszam, powinienem był pamiętać, że ta maszyna jest zdecydowanie niestandardowa, po podłączeniu różnych niestandardowych
libc
implementacji do celów naukowych ;-)Ponieważ
itoa()
jest to rzeczywiście niestandardowe, o czym wspomniało kilku pomocnych komentatorów, najlepiej jest użyćsprintf(target_string,"%d",source_int)
lub (jeszcze lepiej, ponieważ jest bezpieczny przed przepełnieniem bufora)snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int)
. Wiem, że to nie jest tak zwięzłe ani fajne, jakitoa()
, ale przynajmniej możesz napisać raz, biegać wszędzie (tm) ;-)Oto stara (zredagowana) odpowiedź
Masz rację twierdząc, że domyślna
gcc libc
wersja nie obejmujeitoa()
, jak kilka innych platform, ponieważ technicznie nie jest częścią standardu. Zobacz tutaj, aby uzyskać więcej informacji. Pamiętaj, że musiszOczywiście już to wiesz, ponieważ chciałeś używać
itoa()
na Linuksie po przypuszczalnym użyciu go na innej platformie, ale ... kod (skradziony z powyższego linku) wyglądałby tak:Przykład
Wynik:
Mam nadzieję że to pomoże!
źródło
Jeśli często to nazywasz, porada „po prostu użyj snprintf” może być denerwująca. Oto, czego prawdopodobnie chcesz:
źródło
const
kwalifikatory nie wpływają na typy zwracane przez funkcję - wiedziałbyś o tym, gdybyś włączył ostrzeżenia kompilatora :)const char *
jest wskaźnikiem niebędącym stałym do const, co ma dużo sensu i jest poprawne.const
międzyconst int f (void) { ...
iconst int* f (void) { ...
, ale teraz, gdy wypróbowałem to z kompilatorem, ma to sens.itoa
nie jest standardową funkcją C. Możesz wdrożyć własne. Pojawił się w pierwszym wydaniu języka programowania C Kernighana i Ritchiego , na stronie 60. Drugie wydanie języka programowania C („K & R2”) zawiera następującą implementację , na stronie 64. Książka zwraca uwagę na kilka kwestii związanych z tą implementacją , w tym fakt, że nie obsługuje poprawnie większości liczb ujemnychitoa
Funkcja
reverse
użyta powyżej została zaimplementowana dwie strony wcześniej:źródło
Edycja: właśnie dowiedziałem się,
std::to_string
która jest identyczna w działaniu jak moja własna funkcja poniżej. Został wprowadzony w C ++ 11 i jest dostępny w najnowszych wersjach gcc, przynajmniej od 4.5, jeśli włączysz rozszerzenia c ++ 0x.Nie tylko
itoa
brakuje go w gcc, ale nie jest to najłatwiejsza funkcja w użyciu, ponieważ musisz podać jej bufor. Potrzebowałem czegoś, co można by użyć w wyrażeniu, więc wymyśliłem to:Zwykle byłoby bezpieczniejsze w użyciu
snprintf
zamiast,sprintf
ale bufor jest starannie dobrany, aby był odporny na przepełnienie.Zobacz przykład: http://ideone.com/mKmZVE
źródło
std::
rzeczy itp.Jak napisał Matt J, jest
itoa
, ale to nie jest standard. Twój kod będzie bardziej przenośny, jeśli użyjeszsnprintf
.źródło
Następująca funkcja przydziela wystarczającą ilość pamięci, aby zachować ciąg reprezentujący podaną liczbę, a następnie zapisuje reprezentację ciągu w tym obszarze przy użyciu standardowej
sprintf
metody.Nie zapomnij o
free
zwiększeniu przydzielonej pamięci, gdy jej nie potrzebujesz:NB Ponieważ snprintf kopiuje n-1 bajtów, musimy wywołać snprintf (buf, len + 1, "% ld", n) (nie tylko snprintf (buf, len, "% ld", n))
źródło
itoa
ale nadanie jej innego zachowania niż to, coitoa
faktycznie mają powszechne implementacje . Ta funkcja jest dobrym pomysłem, ale nazwij ją inaczej :) Sugerowałbym również użyciesnprintf
do obliczenia długości bufora zamiast łańcucha zmiennoprzecinkowego; zmiennoprzecinkowe mogą mieć niedokładności wielkości liter narożnych. I nie rzucaj calloclabs
jeśli zajmie to długą liczbę całkowitą. W przeciwnym razie może zostać obcięty.snprintf
do bufora tmp o stałym rozmiarze, na przykład wchar buf[64]
celu uzyskania długości, a następniemalloc
skopiuj do niego. Nie odniesiesz żadnej korzyści zcalloc
overmalloc
, ponieważ piszesz wszystkie bajty. Dodatkowe kopiowanie bardzo krótkiego łańcucha jest mniej złe niż wywołanie log10 zmiennoprzecinkowego. Szybkie przybliżenie za pomocą liczby całkowitej log2 może być jednak przydatne, jeśli masz funkcję skanowania bitów, która niezawodnie będzie wbudowana w coś wydajnego (jakbsr
na x86). (Alternatywnie:malloc
64-bajtowy bufor, a następnierealloc
po znaniu ostatecznej długości.)W Linuksie nie ma takiej funkcji. Zamiast tego używam tego kodu.
źródło
Wypróbowałem własną implementację itoa (), wygląda na to, że działa w systemie binarnym, ósemkowym, dziesiętnym i szesnastkowym
źródło
bezpośrednia kopia do bufora: 64-bitowa liczba całkowita itoa hex:
Uwaga: zmień długi na długi długi dla maszyny 32-bitowej. long to int w przypadku 32-bitowej liczby całkowitej. m jest podstawą. Zmniejszając podstawę, zwiększ liczbę znaków (zmienna i). Zwiększając podstawę, zmniejsz liczbę znaków (lepiej). W przypadku typu danych bez znaku, i staje się po prostu 16 + 1.
źródło
Oto znacznie ulepszona wersja rozwiązania Archana. Działa dla każdej podstawy od 1 do 16 i liczb <= 0 i nie powinien obciążać pamięci.
źródło
Jeśli chcesz je tylko wydrukować:
źródło
Czytanie kodu facetów, którzy zajmują się tym na życie, da ci DŁUGIE SPOSOBY.
Sprawdź, jak zrobili to faceci z MySQL. Źródło jest BARDZO DOBRZE KOMENTARZE i nauczy Cię znacznie więcej niż zhakowanych rozwiązań znalezionych w każdym miejscu.
Implementacja MySQL int2str
Podaję tutaj wspomnianą implementację; link jest tutaj w celach informacyjnych i powinien być używany do czytania pełnej implementacji.
źródło
Ponieważ
itoa()
nie jest to standardem w C, istnieją różne wersje z różnymi podpisami funkcji.char *itoa(int value, char *str, int base);
jest powszechne w * nix.Jeśli brakuje go w Linuksie lub jeśli kod nie chce ograniczać przenośności, kod może uczynić go własnym.
Poniżej znajduje się wersja, która nie ma problemów z problemami z
INT_MIN
buforami i nie obsługuje buforów:NULL
lub zwraca niewystarczający buforNULL
.Poniżej znajduje się wersja C99 lub nowsza, która obsługuje dowolną podstawę [2 ... 36]
W przypadku kodu zgodnego ze standardem C89 i nowszym zamień pętlę wewnętrzną na
źródło
Wewnętrzna implementacja glibc
glibc 2.28 ma wewnętrzną implementację:
który jest używany wewnętrznie w kilku miejscach, ale nie mogłem znaleźć, czy można go odsłonić ani jak.
Przynajmniej powinna to być solidna implementacja, jeśli chcesz ją wyodrębnić.
To pytanie dotyczy tego, jak rzucić własne: Jak przekonwertować int na string w C?
źródło
Wolałbym to: https://github.com/wsq003/itoa_for_linux
Powinna to być najszybsza itoa () w historii. Używamy itoa () zamiast sprintf () ze względu na wydajność, więc najszybsza itoa () z ograniczonymi funkcjami jest rozsądna i warta zachodu.
źródło
Użyłem _itoa (...) na RedHacie 6 i kompilatorze GCC. To działa.
źródło
Zamiana za pomocą snprintf NIE jest zakończona!
Obejmuje tylko bazy: 2, 8, 10, 16, podczas gdy itoa działa dla podstaw od 2 do 36.
Ponieważ szukałem zamiennika bazy 32, myślę, że będę musiał zakodować własną!
źródło
Możesz użyć tego programu zamiast sprintf.
źródło