Dalam pengaturcaraan C, tidak mudah untuk menggunakan makro secara rekursif pada hujah makro. Walau bagaimanapun, menggunakan penyelesaian yang kompleks, adalah mungkin untuk mencapai makro MAP dengan fungsi yang diingini.
Untuk memulakan rekursi, kami mentakrifkan makro MAP_OUT yang berfungsi sebagai pemegang tempat untuk pengembangan makro:
#define MAP_OUT
Seterusnya, kami mencipta dua makro, A dan B, untuk menunjukkan rekursi:
#define A(x) x B MAP_OUT (x) #define B(x) x A MAP_OUT (x)
Menilai A(blah) menghasilkan output berikut:
blah B (blah)
Prapemproses menganggap B(blah) sebagai teks biasa kerana ia belum lagi panggilan makro. Apabila teks ini diproses semula, ia mengembang untuk menghasilkan:
blah blah A (blah)
Dengan terus menyuap keluaran semula ke dalam prapemproses, kami boleh mengekalkan rekursi selama-lamanya.
Untuk mengautomasikan penilaian berulang ini, kami menggunakan EVAL makro:
#define EVAL0(...) __VA_ARGS__ #define EVAL1(...) EVAL0 (EVAL0 (EVAL0 (__VA_ARGS__))) #define EVAL2(...) EVAL1 (EVAL1 (EVAL1 (__VA_ARGS__))) #define EVAL3(...) EVAL2 (EVAL2 (EVAL2 (__VA_ARGS__))) #define EVAL4(...) EVAL3 (EVAL3 (EVAL3 (__VA_ARGS__))) #define EVAL(...) EVAL4 (EVAL4 (EVAL4 (__VA_ARGS__)))
Makro EVAL menyebarkan hujahnya melalui pepohon panggilan makro, mendarabkan kiraan penilaiannya sebanyak 365.
Untuk mengelakkan pengulangan yang tidak berkesudahan, kita memerlukan mekanisme untuk penamatan. Kami mentakrifkan makro khas bernama MAP_END:
#define MAP_END(...)
Apabila dinilai, makro ini tidak melakukan apa-apa, menghentikan rekursi dengan berkesan.
Untuk memilih antara makro rekursif dan penamatan, kami memperkenalkan MAP_NEXT:
#define MAP_NEXT0(item, next, ...) next MAP_OUT #define MAP_NEXT1(item, next) MAP_NEXT0 (item, next, 0) #define MAP_NEXT(item, next) MAP_NEXT1 (MAP_GET_END item, next)
MAP_NEXT membandingkan item semasa dengan penanda senarai akhir (). Ia mengembalikan MAP_END jika ia sepadan, atau parameter seterusnya sebaliknya.
Menggabungkan elemen ini, kami boleh mencipta versi praktikal makro A dan B:
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__) #define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
MAP0 dan MAP1 menggunakan operasi f pada item semasa x. Mereka kemudian menyemak item seterusnya, mengintip, untuk menentukan sama ada untuk meneruskan atau menamatkan rekursi.
Akhir sekali, kami mengikat semuanya bersama-sama dengan makro MAP peringkat atas:
#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
Tempat MAP penanda senarai akhir pada senarai argumen dan melepasinya melalui EVAL.
Dengan menggunakan teknik ini, anda boleh mencapai makro rekursif kefungsian dalam C, membolehkan pemprosesan berasaskan makro yang kompleks.
Atas ialah kandungan terperinci Bagaimanakah anda boleh mencapai fungsi makro rekursif dalam C, walaupun terdapat had pengembangan makro?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!