Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Bagaimanakah Kami Boleh Melaksanakan Makro Rekursif dalam C?

Bagaimanakah Kami Boleh Melaksanakan Makro Rekursif dalam C?

Barbara Streisand
Barbara Streisandasal
2024-11-17 19:49:02139semak imbas

How Can We Implement Recursive Macros in C?

Memahami Rekursi Makro untuk Argumen Makro

Dalam pengaturcaraan C, makro menawarkan alat yang berkuasa untuk manipulasi teks. Satu aspek yang menarik ialah keupayaan untuk menggunakan makro pada hujah makro lain. Walau bagaimanapun, ini memberikan cabaran teknikal, kerana makro rekursif biasanya tidak dibenarkan dalam bahasa.

Masalah: Makro Rekursif

Pertimbangkan senario yang ingin kami buat makro foreach, bernama PRINT_ALL, yang menggunakan makro tertentu, PRINT, pada senarai argumen. Contohnya:

int a = 1, b = 3, d = 0;
PRINT_ALL(a,b,d);

Ini akan menggunakan makro CETAK pada setiap pembolehubah a, b dan d. Pendekatan naif mungkin menggunakan makro rekursif, seperti berikut:

#define FIRST_ARG(arg,...) arg
#define AFTER_FIRST_ARG(arg,...) , ##__VA_ARGS__
#define PRINT(a) printf(#a": %d", a)
#define PRINT_ALL PRINT(FIRST_ARG(__VA_ARGS__)); PRINT_ALL(AFTER_FIRST_ARG(__VA_ARGS__))

Walau bagaimanapun, pendekatan ini menimbulkan dua masalah: makro tidak boleh memanggil diri mereka secara rekursif dan ia tidak mempunyai syarat berhenti untuk menghentikan rekursi.

Penyelesaian Rekursif

Untuk mengatasinya halangan, penyelesaian yang bijak memanfaatkan teknik yang dikenali sebagai makro eval-rekursion. Idea utama adalah untuk mengeluarkan teks makro yang mensimulasikan panggilan makro tanpa menggunakan makro itu sendiri.

Pertimbangkan makro berikut:

#define MAP_OUT

Jika kita mempunyai makro berikut:

#define A(x) x B MAP_OUT (x)
#define B(x) x A MAP_OUT (x)

Menilai makro A(blah) menghasilkan teks output:

blah B (blah)

Teks ini berfungsi sebagai pemegang tempat pengganti makro. Ia boleh dihantar semula ke dalam prapemproses untuk dikembangkan lagi, meneruskan proses penilaian makro.

Untuk memudahkan pengulangan ini, satu siri makro EVAL ditakrifkan:

#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__)))

Setiap makro digunakan pelbagai peringkat penilaian, sekali gus menguatkan kesan makro yang digunakan.

Menghentikan Rekursi

Untuk mengawal rekursi, makro khas, MAP_END, ditakrifkan:

#define MAP_END(...)

Menilai makro ini tidak melakukan apa-apa, menamatkan rekursi dengan berkesan.

Cabaran seterusnya ialah untuk menentukan masa untuk menggunakan MAP_END dan bukannya meneruskan rekursi. Untuk mencapai matlamat ini, makro MAP_NEXT membandingkan item senarai dengan penanda akhir senarai khas. Jika ia sepadan, ia mengembalikan MAP_END; jika tidak, ia mengembalikan parameter seterusnya:

#define MAP_GET_END() 0, MAP_END
#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)

Dengan membina makro MAP_NEXT dengan teliti, kita boleh mengawal sama ada rekursi berterusan atau tamat.

Pelaksanaan Akhir

Menggabungkan blok binaan ini, kita boleh mencipta makro MAP yang berulang ke atas senarai dan menggunakan yang diberikan makro kepada setiap item:

#define MAP(f,...)EVAL(MAP1(f,__VA_ARGS__,(),0))

Makro ini berfungsi dengan meletakkan penanda senarai akhir di hujung senarai, bersama-sama dengan hujah tambahan untuk memastikan pematuhan ANSI. Ia kemudian melepasi senarai melalui berbilang panggilan makro EVAL dan mengembalikan hasilnya.

Teknik ini menyediakan penyelesaian kreatif kepada masalah penggunaan makro pada hujah makro. Ia membolehkan keupayaan manipulasi makro yang canggih, membenarkan pengaturcara memanjangkan fungsi prapemproses dalam cara yang baharu.

Atas ialah kandungan terperinci Bagaimanakah Kami Boleh Melaksanakan Makro Rekursif dalam C?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn