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

Bagaimanakah Kami Boleh Melaksanakan Makro Rekursif dalam C?

Barbara Streisand
Lepaskan: 2024-11-17 19:49:02
asal
242 orang telah melayarinya

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);
Salin selepas log masuk

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__))
Salin selepas log masuk

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
Salin selepas log masuk

Jika kita mempunyai makro berikut:

#define A(x) x B MAP_OUT (x)
#define B(x) x A MAP_OUT (x)
Salin selepas log masuk

Menilai makro A(blah) menghasilkan teks output:

blah B (blah)
Salin selepas log masuk

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__)))
Salin selepas log masuk

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(...)
Salin selepas log masuk

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)
Salin selepas log masuk

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))
Salin selepas log masuk

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!

sumber:php.cn
Kenyataan Laman Web ini
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
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan