Bagaimana untuk Mentakrifkan Makro Yang Beroperasi pada Argumen yang Diserahkan kepada Makro Lain dalam C?

Linda Hamilton
Lepaskan: 2024-11-15 15:02:03
asal
576 orang telah melayarinya

How to Define a Macro That Operates on Arguments Passed to Another Macro in C?

Makro Dalam Argumen Makro

Masalahnya

Bagaimanakah seseorang boleh mentakrifkan makro yang beroperasi pada hujah yang dihantar kepada makro lain? Khususnya, pertimbangkan perkara berikut:

#define PRINT(a) printf(#a": %d", a)
#define PRINT_ALL(...) ? ? ? THE PROBLEM ? ? ? 
Salin selepas log masuk

Penggunaan yang Diingini:

int a = 1, b = 3, d = 0;
PRINT_ALL(a,b,d);
Salin selepas log masuk

Mencapai Rekursi

Makro rekursif boleh dilakukan dalam C menggunakan penyelesaian yang tidak konvensional. Matlamatnya ialah untuk mencipta makro MAP yang menyerupai:

#define PRINT(a) printf(#a": %d", a)
MAP(PRINT, a, b, c) /* Apply PRINT to a, b, and c */
Salin selepas log masuk

Basic Recursion

Kami mulakan dengan mencipta cara untuk mengeluarkan sesuatu yang menyerupai panggilan makro yang tidak dinilai:

#define MAP_OUT
Salin selepas log masuk

Mempertimbangkan makro berikut:

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

Menilai A(blah) menghasilkan teks:

blah B (blah)
Salin selepas log masuk

Prapemproses tidak mengesan rekursi di sini, kerana panggilan B (bla) hanyalah teks pada peringkat ini. Memasukkan semula teks ini ke dalam prapemproses mengembangkannya:

blah blah A (blah)
Salin selepas log masuk

Menilai output ini sekali lagi mengembangkan makro A (bla), melengkapkan rekursi. Proses ini berterusan sehingga output dimasukkan semula ke dalam prapemproses sekali lagi.

Untuk memudahkan penilaian berbilang, kami menggunakan makro EVAL untuk meneruskan argumen ke bawah rantaian panggilan 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__)))
Salin selepas log masuk

Setiap tahap menguatkan usaha pendahulunya, akhirnya menilai input 365 kali. Contohnya, EVAL(A(bla)) menghasilkan 365 salinan blah diikuti oleh B yang tidak dinilai (bla). Persediaan ini menyediakan asas untuk rekursi dalam had kedalaman tindanan tertentu.

Pengesanan Tamat

Halangan seterusnya ialah menentukan masa untuk menamatkan rekursi.

Kami mentakrifkan makro MAP_END sebagai penanda senarai akhir:

#define MAP_END(...)
Salin selepas log masuk

Menilai ini makro tidak melakukan apa-apa, menandakan berakhirnya rekursi.

Untuk memilih antara dua makro, kami menggunakan MAP_NEXT, yang membandingkan item senarai dengan penanda akhir senarai khas ():

#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

MAP_NEXT menentukan sama ada untuk meneruskan atau berhenti berdasarkan item senarai dan item seterusnya. Ia mengembalikan MAP_END jika ia sepadan atau parameter seterusnya sebaliknya.

Menyatukan Semuanya

Dengan komponen ini, kami boleh membina versi A dan B yang boleh digunakan:

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

Makro ini menggunakan operasi f pada item senarai semasa x dan kemudian memeriksa item senarai seterusnya, mengintip, untuk menentukan sama ada untuk meneruskan atau tidak.

Akhir sekali, kami mengumpulkan segala-galanya dalam makro MAP peringkat atas:

#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
Salin selepas log masuk

Makro ini menambah penanda () pada penghujung senarai dan melepasi keseluruhannya melalui EVAL , mengembalikan hasilnya.

Kod ini tersedia sebagai pustaka di GitHub untuk kemudahan anda.

Atas ialah kandungan terperinci Bagaimana untuk Mentakrifkan Makro Yang Beroperasi pada Argumen yang Diserahkan kepada Makro Lain 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