itoa()adalah fungsi yang sangat berguna untuk mengubah angka menjadi string. Linux sepertinya tidak punya itoa(), apakah ada fungsi yang setara atau harus saya gunakan sprintf(str, "%d", num)?
Ada alasan untuk tidak menggunakan gcvt()dari perpustakaan standar?
Subin Sebastian
Jawaban:
100
EDIT: Maaf, saya seharusnya ingat bahwa mesin ini jelas-jelas tidak standar, telah terpasang di berbagai libcimplementasi non-standar untuk keperluan akademik ;-)
Karena itoa()memang tidak standar, seperti yang disebutkan oleh beberapa komentator yang membantu, yang terbaik adalah menggunakan sprintf(target_string,"%d",source_int)atau (lebih baik lagi, karena aman dari buffer overflows) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). Saya tahu itu tidak begitu ringkas atau sejukitoa() , tetapi setidaknya Anda dapat Menulis Sekali, Jalankan Di Mana Saja (tm) ;-)
Inilah jawaban lama (yang diedit)
Anda benar dalam menyatakan bahwa default gcc libctidak termasuk itoa(), seperti beberapa platform lain, karena itu secara teknis tidak menjadi bagian dari standar. Lihat di sini untuk info lebih lanjut. Perhatikan bahwa Anda harus melakukannya
#include<stdlib.h>
Tentu saja Anda sudah tahu ini, karena Anda ingin menggunakannyaitoa() di Linux setelah mungkin menggunakannya di platform lain, tapi ... kodenya (dicuri dari tautan di atas) akan terlihat seperti:
Hmmm, kompilasi itu di Debian memberi saya "referensi tidak jelas ke` itoa '". Mungkin ada yang salah dengan sistem saya.
Adam Pierce
Saya mendapatkan hal yang sama di Ubuntu 8.04. Saya tidak dapat menemukan referensi ke itoa di stdio.h atau stdlib.h baik (tidak mengejutkan karena itu bukan bagian dari standar)
camh
diedit untuk kebenaran, terima kasih kawan! maaf, saya selalu lupa bahwa ini bukan kotak vanilla Linux ;-)
Matt J
Saya telah mengedit jawaban untuk menyertakan argumen ukuran buffer; Saya percaya semuanya sudah sebagaimana mestinya sekarang, saya tidak melihat masalah dengan urutan argumennya sendiri. Apakah saya melewatkan sesuatu?
Matt J
Tidak berfungsi untuk Linux? apa hasil dari pertanyaan / jawaban (Tampaknya bukan standar semua linuxes?)
12
Jika Anda sering menyebutnya, saran "gunakan saja snprintf" dapat mengganggu. Jadi inilah yang mungkin Anda inginkan:
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);}
Ini bukan hanya non-thread safe, juga tidak terlalu aman: - void some_func (char * a, char * b); some_func (itoa (123), itoa (456)); Mau menebak fungsi apa yang diterimanya?
jcoder
Selain itu, constkualifikasi tidak melakukan apa pun pada tipe pengembalian fungsi - Anda akan tahu ini jika Anda menghidupkan peringatan kompiler :)
cat
3
@ kucing Tapi tidak ada jenis pengembalian yang memenuhi syarat const di sini. const char *adalah pointer non-const ke const, yang masuk akal dan benar.
Chortos-2
1
@ Chortos-2 Itu menarik, Anda, tentu saja, sepenuhnya benar - Saya tidak menyadari perbedaan semantik dalam arti constantara const int f (void) { ...dan const int* f (void) { ..., tapi sekarang setelah mencobanya dengan kompiler, masuk akal.
kucing
11
itoabukan fungsi standar C. Anda bisa menerapkannya sendiri. Itu muncul dalam edisi pertama Kernighan dan Ritchie's The C Programming Language , di halaman 60. Edisi kedua The C Programming Language ("K & R2") berisi implementasi berikut itoa, pada halaman 64. Buku ini mencatat beberapa masalah dengan implementasi ini , termasuk fakta bahwa ia tidak menangani angka paling negatif dengan benar
/* 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);}
Fungsi yang reversedigunakan di atas diimplementasikan dua halaman sebelumnya:
#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;}}
Sunting: Saya baru tahustd::to_string yang identik dalam operasi dengan fungsi saya sendiri di bawah ini. Itu diperkenalkan di C ++ 11 dan tersedia dalam versi terbaru gcc, setidaknya pada awal 4,5 jika Anda mengaktifkan ekstensi c ++ 0x.
Tidak hanya itoahilang dari gcc, itu bukan fungsi yang paling mudah digunakan karena Anda perlu memberinya buffer. Saya membutuhkan sesuatu yang bisa digunakan dalam ekspresi jadi saya datang dengan ini:
Fungsi berikut mengalokasikan memori yang cukup untuk menjaga representasi string dari angka yang diberikan dan kemudian menulis representasi string ke area ini menggunakan sprintfmetode standar .
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;}
Jangan lupa untuk freemenambah alokasi memori saat dibutuhkan:
Ini bukan ide yang baik untuk memanggil fungsi Anda, itoatetapi berikan perilaku yang berbeda dengan implementasi umum yang itoasebenarnya dimiliki. Fungsi ini adalah ide yang OK tetapi menyebutnya sesuatu yang lain :) Saya juga menyarankan menggunakan snprintfuntuk menghitung panjang buffer, bukan string floating point; floating point dapat memiliki ketidakakuratan kasus sudut. Dan jangan masukkan calloc
MM
Terima kasih atas sarannya.
mmdemirbas
Ini harus digunakan labsjika akan membutuhkan bilangan bulat panjang. Kalau tidak, mungkin terpotong.
Schwern
snprintfke buffer tmp ukuran tetap ingin char buf[64]mendapatkan panjangnya, lalu mallocsalin ke dalamnya. Anda tidak mendapatkan manfaat apa pun dari callocatas malloc, karena Anda menulis semua byte. Penyalinan ekstra dari string yang sangat pendek kurang buruk daripada harus memanggil floating point log10. Perkiraan cepat dengan integer log2 bisa berguna, jika Anda memiliki fungsi pemindaian bit yang andal akan sejalan dengan sesuatu yang efisien (seperti bsrpada x86). (Alternatif: mallocbuffer 64 byte dan kemudian reallocsetelah Anda tahu panjang akhirnya.)
Peter Cordes
3
Di mana fungsi itoa di Linux?
Tidak ada fungsi seperti itu di Linux. Saya menggunakan kode ini sebagai gantinya.
/*
=============
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;}
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];}
Catatan: ubah panjang ke panjang untuk mesin 32 bit. panjang ke int jika untuk integer 32 bit. m adalah radix. Ketika mengurangi radix, menambah jumlah karakter (variabel i). Saat menambah radix, kurangi jumlah karakter (lebih baik). Dalam hal tipe data yang tidak ditandatangani, saya hanya menjadi 16 + 1.
Membaca kode orang-orang yang melakukannya untuk mencari nafkah akan memberi Anda CARA PANJANG.
Lihatlah bagaimana orang-orang dari MySQL melakukannya. Sumbernya SANGAT BAIK DIPERBOLEHKAN dan akan mengajarkan Anda lebih dari sekadar solusi yang ditemukan di semua tempat.
Saya memberikan implementasi yang disebutkan di sini; tautan di sini untuk referensi dan harus digunakan untuk membaca implementasi penuh.
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;}
Tautan ke solusi potensial selalu diterima, tetapi harap tambahkan konteks di sekitar tautan sehingga sesama pengguna Anda akan mengetahui apa itu dan mengapa ada di sana. Selalu kutip bagian yang paling relevan dari tautan penting, jika situs target tidak dapat dijangkau atau offline secara permanen. Mempertimbangkan bahwa menjadi lebih dari sekadar tautan ke situs eksternal adalah kemungkinan alasan mengapa dan bagaimana beberapa jawaban dihapus? .
Tunaki
1
Jadi, apa bagusnya cuplikan yang Anda poskan di sini? Apa yang harus diwaspadai oleh pembaca di masa depan?
Martijn Pieters
1
Di mana fungsi itoa di Linux?
Karena itoa()tidak standar dalam C, berbagai versi dengan berbagai tanda tangan fungsi ada. char *itoa(int value, char *str, int base);umum di * nix.
Haruskah itu hilang dari Linux atau jika kode tidak ingin membatasi portabilitas, kode dapat membuatnya sendiri.
Di bawah ini adalah versi yang tidak memiliki masalah dengan INT_MINdan menangani buffer masalah: NULLatau buffer tidak mencukupi 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);}
Di bawah ini adalah versi C99 atau lebih baru yang menangani basis apa pun [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);}
Untuk kode yang sesuai dengan C89 dan selanjutnya, ganti loop dalam dengan
div_t qr;do{
qr = div(neg_num, base);*--p ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
neg_num = qr.quot;}while(neg_num);
Ini harus menjadi itoa tercepat () yang pernah ada. Kami menggunakan itoa () alih-alih sprintf () karena alasan kinerja, jadi itoa tercepat () dengan fitur terbatas masuk akal dan bermanfaat.
Ada begitu banyak bug dalam kode ini: 1) Tidak benar-benar mengkonversi hex dengan benar. 2) Tidak mengonversi 0 sama sekali. 3) Tidak bekerja dengan angka negatif. 4) Tidak memeriksa buffer overrun. Saya akan segera memposting versi perbaikan kode ini.
sprintf(str, "%d", num)
? Apakah ini jauh lebih lambatitoa
?itoa
memungkinkan konversi basis sewenang-wenang,printf
specifier tidak.gcvt()
dari perpustakaan standar?Jawaban:
EDIT: Maaf, saya seharusnya ingat bahwa mesin ini jelas-jelas tidak standar, telah terpasang di berbagai
libc
implementasi non-standar untuk keperluan akademik ;-)Karena
itoa()
memang tidak standar, seperti yang disebutkan oleh beberapa komentator yang membantu, yang terbaik adalah menggunakansprintf(target_string,"%d",source_int)
atau (lebih baik lagi, karena aman dari buffer overflows)snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int)
. Saya tahu itu tidak begitu ringkas atau sejukitoa()
, tetapi setidaknya Anda dapat Menulis Sekali, Jalankan Di Mana Saja (tm) ;-)Inilah jawaban lama (yang diedit)
Anda benar dalam menyatakan bahwa default
gcc libc
tidak termasukitoa()
, seperti beberapa platform lain, karena itu secara teknis tidak menjadi bagian dari standar. Lihat di sini untuk info lebih lanjut. Perhatikan bahwa Anda harus melakukannyaTentu saja Anda sudah tahu ini, karena Anda ingin menggunakannya
itoa()
di Linux setelah mungkin menggunakannya di platform lain, tapi ... kodenya (dicuri dari tautan di atas) akan terlihat seperti:Contoh
Keluaran:
Semoga ini membantu!
sumber
Jika Anda sering menyebutnya, saran "gunakan saja snprintf" dapat mengganggu. Jadi inilah yang mungkin Anda inginkan:
sumber
const
kualifikasi tidak melakukan apa pun pada tipe pengembalian fungsi - Anda akan tahu ini jika Anda menghidupkan peringatan kompiler :)const char *
adalah pointer non-const ke const, yang masuk akal dan benar.const
antaraconst int f (void) { ...
danconst int* f (void) { ...
, tapi sekarang setelah mencobanya dengan kompiler, masuk akal.itoa
bukan fungsi standar C. Anda bisa menerapkannya sendiri. Itu muncul dalam edisi pertama Kernighan dan Ritchie's The C Programming Language , di halaman 60. Edisi kedua The C Programming Language ("K & R2") berisi implementasi berikutitoa
, pada halaman 64. Buku ini mencatat beberapa masalah dengan implementasi ini , termasuk fakta bahwa ia tidak menangani angka paling negatif dengan benarFungsi yang
reverse
digunakan di atas diimplementasikan dua halaman sebelumnya:sumber
Sunting: Saya baru tahu
std::to_string
yang identik dalam operasi dengan fungsi saya sendiri di bawah ini. Itu diperkenalkan di C ++ 11 dan tersedia dalam versi terbaru gcc, setidaknya pada awal 4,5 jika Anda mengaktifkan ekstensi c ++ 0x.Tidak hanya
itoa
hilang dari gcc, itu bukan fungsi yang paling mudah digunakan karena Anda perlu memberinya buffer. Saya membutuhkan sesuatu yang bisa digunakan dalam ekspresi jadi saya datang dengan ini:Biasanya itu akan lebih aman untuk digunakan
snprintf
daripadasprintf
tetapi buffer dengan hati-hati berukuran kebal terhadap overrun.Lihat contoh: http://ideone.com/mKmZVE
sumber
std::
barang dll.Seperti yang ditulis Matt J, ada
itoa
, tapi itu bukan standar. Kode Anda akan lebih portabel jika Anda gunakansnprintf
.sumber
Fungsi berikut mengalokasikan memori yang cukup untuk menjaga representasi string dari angka yang diberikan dan kemudian menulis representasi string ke area ini menggunakan
sprintf
metode standar .Jangan lupa untuk
free
menambah alokasi memori saat dibutuhkan:NB Saat snprintf menyalin n-1 byte, kita harus memanggil snprintf (buf, len + 1, "% ld", n) (bukan hanya snprintf (buf, len, "% ld", n))
sumber
itoa
tetapi berikan perilaku yang berbeda dengan implementasi umum yangitoa
sebenarnya dimiliki. Fungsi ini adalah ide yang OK tetapi menyebutnya sesuatu yang lain :) Saya juga menyarankan menggunakansnprintf
untuk menghitung panjang buffer, bukan string floating point; floating point dapat memiliki ketidakakuratan kasus sudut. Dan jangan masukkan calloclabs
jika akan membutuhkan bilangan bulat panjang. Kalau tidak, mungkin terpotong.snprintf
ke buffer tmp ukuran tetap inginchar buf[64]
mendapatkan panjangnya, lalumalloc
salin ke dalamnya. Anda tidak mendapatkan manfaat apa pun daricalloc
atasmalloc
, karena Anda menulis semua byte. Penyalinan ekstra dari string yang sangat pendek kurang buruk daripada harus memanggil floating point log10. Perkiraan cepat dengan integer log2 bisa berguna, jika Anda memiliki fungsi pemindaian bit yang andal akan sejalan dengan sesuatu yang efisien (sepertibsr
pada x86). (Alternatif:malloc
buffer 64 byte dan kemudianrealloc
setelah Anda tahu panjang akhirnya.)Tidak ada fungsi seperti itu di Linux. Saya menggunakan kode ini sebagai gantinya.
sumber
saya mencoba implementasi itoa () saya sendiri, sepertinya berfungsi dalam biner, oktal, desimal dan hex
sumber
copy langsung ke buffer: 64 bit integer itoa hex:
Catatan: ubah panjang ke panjang untuk mesin 32 bit. panjang ke int jika untuk integer 32 bit. m adalah radix. Ketika mengurangi radix, menambah jumlah karakter (variabel i). Saat menambah radix, kurangi jumlah karakter (lebih baik). Dalam hal tipe data yang tidak ditandatangani, saya hanya menjadi 16 + 1.
sumber
Ini adalah versi yang lebih baik dari solusi Archana. Ini bekerja untuk semua radix 1-16, dan angka <= 0, dan itu tidak akan merusak memori.
sumber
Jika Anda hanya ingin mencetaknya:
sumber
Membaca kode orang-orang yang melakukannya untuk mencari nafkah akan memberi Anda CARA PANJANG.
Lihatlah bagaimana orang-orang dari MySQL melakukannya. Sumbernya SANGAT BAIK DIPERBOLEHKAN dan akan mengajarkan Anda lebih dari sekadar solusi yang ditemukan di semua tempat.
Implementasi int2str dari MySQL
Saya memberikan implementasi yang disebutkan di sini; tautan di sini untuk referensi dan harus digunakan untuk membaca implementasi penuh.
sumber
Karena
itoa()
tidak standar dalam C, berbagai versi dengan berbagai tanda tangan fungsi ada.char *itoa(int value, char *str, int base);
umum di * nix.Haruskah itu hilang dari Linux atau jika kode tidak ingin membatasi portabilitas, kode dapat membuatnya sendiri.
Di bawah ini adalah versi yang tidak memiliki masalah dengan
INT_MIN
dan menangani buffer masalah:NULL
atau buffer tidak mencukupiNULL
.Di bawah ini adalah versi C99 atau lebih baru yang menangani basis apa pun [2 ... 36]
Untuk kode yang sesuai dengan C89 dan selanjutnya, ganti loop dalam dengan
sumber
implementasi internal glibc
glibc 2.28 memiliki implementasi internal:
yang digunakan di beberapa tempat secara internal, tetapi saya tidak dapat menemukan apakah itu bisa diekspos atau bagaimana.
Setidaknya itu harus menjadi implementasi yang kuat jika Anda ingin mengekstraknya.
Pertanyaan ini menanyakan bagaimana cara menggulung sendiri: Bagaimana mengonversi int ke string dalam C?
sumber
Saya lebih suka ini: https://github.com/wsq003/itoa_for_linux
Ini harus menjadi itoa tercepat () yang pernah ada. Kami menggunakan itoa () alih-alih sprintf () karena alasan kinerja, jadi itoa tercepat () dengan fitur terbatas masuk akal dan bermanfaat.
sumber
Saya telah menggunakan _itoa (...) pada RedHat 6 dan GCC compiler. Berhasil.
sumber
Pengganti dengan snprintf TIDAK lengkap!
Ini hanya mencakup basis: 2, 8, 10, 16, sedangkan itoa bekerja untuk basis antara 2 dan 36.
Karena saya mencari pengganti base 32, saya kira saya harus membuat kode sendiri!
sumber
Anda dapat menggunakan program ini alih-alih sprintf.
sumber