Saya memiliki fungsi yang menerima string, yaitu:
void log_out(char *);
Dalam memanggilnya, saya perlu membuat string berformat dengan cepat seperti:
int i = 1;
log_out("some text %d", i);
Bagaimana saya melakukan ini di ANSI C?
Hanya saja, karena sprintf()
mengembalikan int, ini berarti saya harus menulis setidaknya 3 perintah, seperti:
char *s;
sprintf(s, "%d\t%d", ix, iy);
log_out(s);
Adakah cara untuk mempersingkat ini?
Jawaban:
Gunakan sprintf .
Parameter:
Contoh:
sumber
Jika Anda memiliki sistem yang sesuai dengan POSIX-2008 (semua Linux modern), Anda dapat menggunakan fungsi yang aman dan nyaman
asprintf()
: Ini akan memilikimalloc()
cukup memori untuk Anda, Anda tidak perlu khawatir tentang ukuran string maksimum. Gunakan seperti ini:Ini adalah upaya minimum yang bisa Anda lakukan untuk membuat string dengan cara yang aman. The
sprintf()
kode yang Anda berikan dalam pertanyaan secara mendalam cacat:Tidak ada memori yang dialokasikan di belakang penunjuk. Anda menulis string ke lokasi acak dalam memori!
Bahkan jika Anda telah menulis
Anda akan berada dalam masalah besar, karena Anda tidak tahu angka apa yang harus dimasukkan ke dalam tanda kurung.
Bahkan jika Anda telah menggunakan varian "aman"
snprintf()
, Anda masih akan menghadapi bahaya jika string Anda terpotong. Saat menulis ke file log, itu adalah masalah yang relatif kecil, tetapi berpotensi memotong dengan tepat informasi yang seharusnya berguna. Juga, itu akan memotong karakter garis akhir, menempelkan baris log berikutnya ke akhir baris yang tidak berhasil Anda tulis.Jika Anda mencoba menggunakan kombinasi
malloc()
dansnprintf()
untuk menghasilkan perilaku yang benar dalam semua kasus, Anda akan mendapatkan kode kira-kira dua kali lebih banyak daripada yang saya berikanasprintf()
, dan pada dasarnya memprogram ulang fungsionalitasasprintf()
.Jika Anda ingin menyediakan pembungkus
log_out()
yang dapat mengambilprintf()
daftar parameter gaya itu sendiri, Anda dapat menggunakan varianvasprintf()
yang mengambil ava_list
sebagai argumen. Berikut adalah implementasi yang sangat aman dari pembungkus seperti itu:sumber
asprintf()
itu bukan bagian dari standar C 2011 atau bagian dari POSIX, bahkan bukan POSIX 2008 atau 2013. Ini adalah bagian dari TR 27431-2: lihat Apakah Anda menggunakan fungsi 'aman' TR 24731?Kedengarannya bagi saya seperti Anda ingin dapat dengan mudah meneruskan string yang dibuat menggunakan pemformatan gaya printf ke fungsi yang sudah Anda miliki yang membutuhkan string sederhana. Anda dapat membuat fungsi pembungkus menggunakan
stdarg.h
fasilitas danvsnprintf()
(yang mungkin tidak tersedia, tergantung pada kompiler / platform Anda):Untuk platform yang tidak menyediakan implementasi yang baik (atau implementasi apa pun) dari rangkaian
snprintf()
rutinitas, saya telah berhasil menggunakan domain hampir publiksnprintf()
dari Holger Weiss .sumber
Jika Anda memiliki kode untuk
log_out()
, tulis ulang. Kemungkinan besar, Anda dapat melakukan:Jika ada informasi logging tambahan yang diperlukan, yang dapat dicetak sebelum atau sesudah pesan ditampilkan. Ini menghemat alokasi memori dan ukuran buffer yang meragukan dan seterusnya dan seterusnya. Anda mungkin perlu menginisialisasi
logfp
ke nol (penunjuk nol) dan memeriksa apakah itu nol dan membuka file log yang sesuai - tetapi kode yang adalog_out()
harus menangani itu juga.Keuntungan dari solusi ini adalah Anda dapat dengan mudah menyebutnya sebagai varian dari
printf()
; memang, ini adalah varian kecil padaprintf()
.Jika Anda tidak memiliki kodenya
log_out()
, pertimbangkan apakah Anda dapat menggantinya dengan varian seperti yang diuraikan di atas. Apakah Anda dapat menggunakan nama yang sama akan bergantung pada kerangka aplikasi Anda dan sumber utama darilog_out()
fungsi saat ini . Jika ada di file objek yang sama dengan fungsi lain yang sangat diperlukan, Anda harus menggunakan nama baru. Jika Anda tidak dapat mengetahui cara mereplikasi dengan tepat, Anda harus menggunakan beberapa varian seperti yang diberikan dalam jawaban lain yang mengalokasikan jumlah memori yang sesuai.Jelas, Anda sekarang memanggil
log_out_wrapper()
alih - alihlog_out()
- tetapi alokasi memori dan seterusnya dilakukan sekali. Saya berhak untuk mengalokasikan ruang secara berlebihan dengan satu byte yang tidak perlu - saya belum memeriksa ulang apakah panjang yang dikembalikan olehvsnprintf()
termasuk penghentian null atau tidak.sumber
Jangan gunakan sprintf.
Ini akan meluap-luap String-Buffer Anda dan merusak Program Anda.
Selalu gunakan snprintf
sumber
Saya belum melakukan ini, jadi saya hanya akan menunjukkan jawaban yang benar.
C memiliki ketentuan untuk fungsi yang mengambil jumlah operan yang tidak ditentukan, menggunakan
<stdarg.h>
header. Anda dapat mendefinisikan fungsi Anda sebagaivoid log_out(const char *fmt, ...);
, dan mendapatkan diva_list
dalam fungsi tersebut. Kemudian Anda dapat mengalokasikan memori dan memanggilvsprintf()
dengan memori yang dialokasikan, format, danva_list
.Bergantian, Anda dapat menggunakan ini untuk menulis fungsi analog
sprintf()
yang akan mengalokasikan memori dan mengembalikan string yang diformat, menghasilkannya kurang lebih seperti di atas. Ini akan menjadi kebocoran memori, tetapi jika Anda baru saja keluar, itu mungkin tidak masalah.sumber
http://www.gnu.org/software/hello/manual/libc/Variable-Arguments-Output.html memberikan contoh berikut untuk dicetak ke stderr. Anda dapat memodifikasinya untuk menggunakan fungsi log Anda:
Alih-alih vfprintf, Anda perlu menggunakan vsprintf di mana Anda perlu menyediakan buffer yang memadai untuk mencetak.
sumber