Saya ingin membuat makro C yang membuat fungsi dengan nama berdasarkan nomor baris. Saya pikir saya bisa melakukan sesuatu seperti (fungsi sebenarnya akan memiliki pernyataan di dalam kurung):
#define UNIQUE static void Unique_##__LINE__(void) {}
Yang saya harap akan berkembang menjadi seperti:
static void Unique_23(void) {}
Itu tidak berhasil. Dengan penggabungan token, makro pemosisian diperlakukan secara harfiah, yang akhirnya meluas ke:
static void Unique___LINE__(void) {}
Apakah ini mungkin dilakukan?
(Ya, ada alasan nyata saya ingin melakukan ini tidak peduli betapa tidak berguna ini tampaknya).
c
macros
concatenation
token
DD.
sumber
sumber
__LINE__
(meskipun itu adalah kasus penggunaan umum.Jawaban:
Masalahnya adalah ketika Anda memiliki pengganti makro, preprocessor hanya akan memperluas makro secara rekursif jika baik operator merangkai
#
maupun operator penempelan token##
diterapkan padanya. Jadi, Anda harus menggunakan beberapa lapisan tambahan tipuan, Anda dapat menggunakan operator penempelan token dengan argumen yang diperluas secara rekursif:Kemudian,
__LINE__
akan diperluas ke nomor baris selama perluasanUNIQUE
(karena tidak terlibat dengan salah satu#
atau##
), dan kemudian penempelan token terjadi selama perluasanTOKENPASTE
.Perlu juga dicatat bahwa ada juga
__COUNTER__
makro, yang meluas ke bilangan bulat baru setiap kali dievaluasi, jika Anda perlu memiliki beberapa contohUNIQUE
makro pada baris yang sama. Catatan:__COUNTER__
didukung oleh MS Visual Studio, GCC (sejak V4.3), dan Clang, tetapi tidak standar C.sumber
__COUNTER__
makro tidak bekerja untuk saya di gcc; meskipun__LINE__
salah satunya berfungsi seperti yang diiklankan.GCC tidak memerlukan "pembungkusan" (atau realisasi) kecuali hasilnya harus "dirangkai". Gcc memiliki fitur tetapi SEMUA dapat dilakukan dengan C versi 1 biasa (dan beberapa orang berpendapat Berkeley 4.3 C jauh lebih cepat sehingga perlu dipelajari cara menggunakannya).
** Dentang (llvm) TIDAK MELAKUKAN RUANG PUTIH DENGAN BENAR untuk perluasan makro - ia menambahkan spasi (yang tentunya menghancurkan hasil sebagai Pengenal C untuk pra-pemrosesan lebih lanjut) **, dentang tidak melakukan # atau * perluasan makro seperti yang diharapkan oleh C Preprocessor selama beberapa dekade. Contoh utama adalah kompilasi X11, makro "Concat3" rusak, hasilnya sekarang adalah MISNAMED C Identifier, yang tentu saja gagal dibangun. dan saya mulai merasa gagal membangun adalah profesi mereka.
Saya pikir jawabannya di sini adalah "C baru yang melanggar standar adalah C buruk", peretasan ini selalu memilih untuk (ruang nama clobber) mereka mengubah default tanpa alasan tetapi tidak benar-benar "meningkatkan C" (kecuali mereka sendiri mengatakan demikian: yang i say adalah alat yang dibuat untuk menjelaskan mengapa mereka lolos dengan semua kerusakan yang belum ada yang membuat mereka bertanggung jawab).
Bukan masalah bahwa pra-pemroses C sebelumnya tidak mendukung UNIq_ () __ karena mereka mendukung #pragma yang memungkinkan "peretasan merek kompilator dalam kode ditandai sebagai peretasan" dan juga berfungsi dengan baik TANPA memengaruhi standar: sama seperti mengubah defaultnya adalah kerusakan wonton yang tidak berguna, dan sama seperti mengubah fungsi yang dilakukan saat menggunakan nama yang sama (namespace clobbering) adalah ... malware menurut saya
sumber