Katakanlah saya memiliki fungsi C yang mengambil sejumlah variabel argumen: Bagaimana saya bisa memanggil fungsi lain yang mengharapkan sejumlah variabel argumen dari dalamnya, melewati semua argumen yang masuk ke fungsi pertama?
Contoh:
void format_string(char *fmt, ...);
void debug_print(int dbg_lvl, char *fmt, ...) {
format_string(fmt, /* how do I pass all the arguments from '...'? */);
fprintf(stdout, fmt);
}
c
variadic-functions
Vicent Marti
sumber
sumber
Jawaban:
Untuk meneruskan elips, Anda harus mengubahnya menjadi va_list dan menggunakannya va_list di fungsi kedua Anda. Secara khusus;
sumber
format_string
tidak akan berguna juga, karena harus melakukan modifikasi in-situ ke fmt, yang tentunya juga tidak boleh dilakukan. Opsi akan termasuk menyingkirkan format_string sama sekali dan menggunakan vfprintf, tetapi itu membuat asumsi tentang apa sebenarnya format_string, atau format_string mengembalikan string yang berbeda. Saya akan mengedit jawaban untuk menunjukkan yang terakhir.argptr
dan fungsi yang dipanggil menggunakanargptr
sama sekali, satu-satunya hal yang aman untuk dilakukan adalah memanggilva_end()
dan kemudian restartva_start(argptr, fmt);
untuk menginisialisasi ulang. Atau Anda dapat menggunakanva_copy()
jika sistem Anda mendukungnya (C99 dan C11 memerlukannya; C89 / 90 tidak).Tidak ada cara untuk memanggil (misalnya) printf tanpa mengetahui berapa banyak argumen yang Anda sampaikan, kecuali Anda ingin masuk ke trik nakal dan non-portabel.
Solusi yang umum digunakan adalah untuk selalu memberikan bentuk alternatif dari fungsi vararg, sehingga
printf
memilikivprintf
yangva_list
menggantikan...
. The...
versi hanya pembungkus sekitarva_list
versi.sumber
vsyslog
ini tidak sesuai dengan POSIX .Fungsi Variadik bisa berbahaya . Ini trik yang lebih aman:
sumber
#define callVardicMethodSafely(values...) ({ values *v = { values }; _actualFunction(values, sizeof(v) / sizeof(*v)); })
Dalam C ++ 0x yang luar biasa Anda bisa menggunakan templat variadic:
sumber
Anda dapat menggunakan unit inline untuk panggilan fungsi. (dalam kode ini saya menganggap argumen adalah karakter).
sumber
Anda dapat mencoba makro juga.
sumber
Meskipun Anda dapat menyelesaikan masalah pemasangan formatter dengan menyimpannya di buffer lokal terlebih dahulu, tetapi itu perlu stack dan terkadang bisa menjadi masalah untuk ditangani. Saya mencoba mengikuti dan tampaknya berfungsi dengan baik.
Semoga ini membantu.
sumber
Solusi Ross sedikit beres-beres. Hanya berfungsi jika semua argumen adalah pointer. Juga implementasi bahasa harus mendukung penghapusan koma sebelumnya jika
__VA_ARGS__
kosong (baik Visual Studio C ++ dan GCC lakukan).sumber
Katakanlah Anda memiliki fungsi variadik khas yang Anda tulis. Karena setidaknya satu argumen diperlukan sebelum variadic
...
, Anda harus selalu menulis argumen tambahan dalam penggunaan.Atau apakah Anda
Jika Anda membungkus fungsi variadic Anda dalam makro, Anda tidak perlu arg sebelumnya. Pertimbangkan contoh ini:
Ini jelas jauh lebih nyaman, karena Anda tidak perlu menentukan argumen awal setiap kali.
sumber
Saya tidak yakin apakah ini bekerja untuk semua kompiler, tetapi sejauh ini berhasil bagi saya.
Anda dapat menambahkan ... ke inner_func () jika Anda mau, tetapi Anda tidak membutuhkannya. Ini berfungsi karena va_start menggunakan alamat variabel yang diberikan sebagai titik awal. Dalam hal ini, kami memberikan referensi ke variabel di func (). Jadi ia menggunakan alamat itu dan membaca variabel setelah itu di stack. Fungsi inner_func () membaca dari alamat stack dari func (). Jadi itu hanya berfungsi jika kedua fungsi menggunakan segmen stack yang sama.
Macro va_start dan va_arg umumnya akan berfungsi jika Anda memberi mereka var sebagai titik awal. Jadi jika mau, Anda bisa meneruskan pointer ke fungsi lain dan menggunakannya juga. Anda dapat membuat makro sendiri dengan cukup mudah. Semua makro lakukan adalah mengetikkan alamat memori. Namun membuat mereka bekerja untuk semua kompiler dan konvensi pemanggilan itu mengganggu. Jadi umumnya lebih mudah menggunakan yang datang dengan kompiler.
sumber