最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言遞歸宏的具體使用

 更新時間:2025年11月07日 09:13:01   作者:這兒有一堆花  
本文介紹了階段進行多次符號替換,從而模擬遞歸效果,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、先把地基壓實:C 宏并不會“真遞歸”

C 標(biāo)準(zhǔn)(以 C17 為例)規(guī)定了宏展開的單次掃描不立即再次展開相同標(biāo)識符的規(guī)則。簡化地說,這段代碼不會像函數(shù)那樣在運行期一層層壓棧,而是在編譯前由預(yù)處理器做一次(或多次)符號替換。

#define SELF(X) SELF(X)  // 期待“遞歸”?不會成功
int x = SELF(1);         // 預(yù)處理器直接拒絕/死循環(huán)保護

要點:所謂“遞歸宏”,實際上是通過構(gòu)造“延遲展開(defer)”和“多輪掃描(rescan)”,讓預(yù)處理器在后續(xù)輪次再去展開目標(biāo),從而模擬“遞歸”的效果。

二、故事線索:一份命令表,三處復(fù)用

項目里有一張“命令定義清單”。經(jīng)典解法是 X-Macro:把數(shù)據(jù)集中放在一個表里,用不同的宏姿勢多次“播放”。

// commands.def —— 只維護這一份
// 格式: X(標(biāo)識符, "字符串", 編碼)
X(CMD_FOO, "foo", 0x01)
X(CMD_BAR, "bar", 0x02)
X(CMD_BAZ, "baz", 0x03)

然后在不同位置這樣用:

// 1) 枚舉
#define X(name, str, code) name = code,
enum Command {
#include "commands.def"
};
#undef X

// 2) 字符串?dāng)?shù)組
#define X(name, str, code) [code] = str,
const char* kCmdName[0x100] = {
#include "commands.def"
};
#undef X

這已經(jīng)解決了 “一處維護、多處生成” 的大半問題。可一旦想“遍歷變長參數(shù)”或“編出嵌套結(jié)構(gòu)”,就會撞到 X-Macro 的邊界,于是“遞歸宏”的戲份來了。

三、遞歸宏的核心技巧:延遲與阻斷

想象成一句“別現(xiàn)在展開,等下一輪再說”。常見做法是準(zhǔn)備三個工具宏:

#define EMPTY()
#define DEFER(id) id EMPTY()            // 把 id 的展開推遲一輪
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)() // 阻斷+再延期
#define EXPAND(...) __VA_ARGS__        // 有時配合編譯器做再展開

它們本身不神秘,重點在讓預(yù)處理器別一次性把所有層級吃完。這樣才能模擬“你先記著,下一口再嚼”的節(jié)奏。

例子1:給可變參數(shù)“逐個套殼”(MAP)

目標(biāo):把 MAP(WRAP, A, B, C) 變成 WRAP(A) WRAP(B) WRAP(C)。一份最小可用(且便于理解)的實現(xiàn)如下:

// 判空與“還有參數(shù)嗎”的探針(簡化版)
#define EVAL(...)  EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) __VA_ARGS__

#define CAT(a,b) a##b
#define PROBE() ~, 1
#define IS_PROBE(...) CAT(IS_PROBE_, __VA_ARGS__)
#define IS_PROBE_~ , 0

#define SECOND(a, b, ...) b
#define NOT(x) IS_PROBE(CAT(PROBE_ , x))
#define BOOL(x) NOT(NOT(x))
#define IF(c) CAT(IF_, c)
#define IF_1(t, ...) t
#define IF_0(t, ...) __VA_ARGS__

// 取第一個參數(shù)與余下參數(shù)
#define HEAD(x, ...) x
#define TAIL(x, ...) __VA_ARGS__

// 檢測是否還有參數(shù)(極簡近似)
#define HAS_ARGS(...) BOOL(SECOND(__VA_ARGS__ , ~))

// 遞歸樣式的 MAP
#define MAP(f, first, ...)            \
  f(first)                            \
  IF(HAS_ARGS(__VA_ARGS__))(          \
      OBSTRUCT()(DEFER(MAP)()(f, __VA_ARGS__)) \
  , /* empty */)

#define WRAP(x) [x]

/* 使用 */
EVAL(MAP(WRAP, A, B, C))  // 結(jié)果: [A] [B] [C]

這里的關(guān)鍵就是 OBSTRUCTDEFER:當(dāng) MAP 需要“再處理余下參數(shù)”時,它不立刻調(diào)用自己,而是故意推遲一個展開節(jié)拍,交給下一輪掃描,于是在視覺上形成了“遞歸”。

例子2:把鍵值對轉(zhuǎn)成結(jié)構(gòu)初始化

當(dāng)命令表變復(fù)雜,可能出現(xiàn)嵌套:

// pairs.def
P(kFoo,  1)
P(kBar,  2)
P(kBaz,  3)

想要生成:

struct Item { const char* name; int code; };
struct Item items[] = {
  {"kFoo", 1}, {"kBar", 2}, {"kBaz", 3}
};

可以在 P 前后套“遞歸 MAP”:

#define AS_ITEM(pair_name, code) { #pair_name, code },

#define LIST(...) EVAL(MAP(AS_ITEM, __VA_ARGS__))

struct Item items[] = {
  LIST(
    // 讓 def 文件只管內(nèi)容,外面用“展開器”來遍歷
    #define P(name, code) name, code
    #include "pairs.def"
    #undef P
  )
};

四、工程可落地的三板斧

1)把“算法”封到獨立頭文件:例如 pp_map.h 專管 MAP/CHAIN/REPEAT 等。業(yè)務(wù)側(cè)只 include,不反復(fù)復(fù)制宏魔法。
2)給每條“魔法”寫一次“快照單測”:對編譯后產(chǎn)物用 static_assert 或數(shù)組大小校驗,確保未來改動不把生成結(jié)果弄壞。
3)設(shè)置最大深度:遞歸宏最終還是有限步“吃完”。為 MAP 等提供“最大次數(shù)保險絲”,避免極端輸入卡在預(yù)處理階段。

// 例如硬性限制最多處理 64 項
#define LIMIT_64(...) __VA_ARGS__
#define MAP_LIMITED(f, ...) LIMIT_64(EVAL(MAP(f, __VA_ARGS__)))

五、與現(xiàn)成庫牽手:Boost.Preprocessor 的啟發(fā)

C++ 項目常用的 Boost.Preprocessor 在 C 代碼里也能借鑒思想(宏只是預(yù)處理期產(chǎn)物)。它提供 BOOST_PP_REPEAT、BOOST_PP_SEQ_FOR_EACH 等成熟原語,足以覆蓋多數(shù)“列表掃描”“計數(shù)”“拼接”需求。
Boost.Preprocessor 官網(wǎng)https://www.boost.org/doc/libs/release/libs/preprocessor/

六、再回到故事:三處生成,一處真相

命令清單只維護在一處;
通過 X-Macro 完成“結(jié)構(gòu)性多次播放”;
在需要“變長/嵌套遍歷”的地方,用**遞歸宏(延遲展開)**把“列表加工”補齊。
落地后,增刪命令就只改一行,枚舉、字符串、解析器保持同步。

七、邊界與避坑清單(工程經(jīng)驗濃縮)

  • 可讀性:宏層層交錯非?;逎?。務(wù)必寫注釋,尤其解釋 DEFER/OBSTRUCT 的意圖與“多輪掃描”的必要性。
  • 編譯器差異:不同編譯器對“再次掃描”的策略略有差別;遇到怪異行為,優(yōu)先用 EVAL/EVAL1/EVAL2... 逼出足夠的展開輪次。
  • 調(diào)試手段-E 導(dǎo)出預(yù)處理結(jié)果;或在 IDE 里開啟“預(yù)處理產(chǎn)物”查看。
  • 邊做邊收斂:一旦邏輯成長為“編程語言中的編程語言”,要審視是否引入 Python/生成腳本更合適。

九、再給兩個“像真遞歸”的小玩具

計數(shù):編譯期統(tǒng)計參數(shù)個數(shù)

#define ARG_N( \
 _1,_2,_3,_4,_5,_6,_7,_8,_9,_10, \
 _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
 N, ...) N
#define RSEQ() \
  20,19,18,17,16,15,14,13,12,11,10, \
   9, 8, 7, 6, 5, 4, 3, 2, 1, 0

#define NARGS_(...) ARG_N(__VA_ARGS__)
#define NARGS(...) NARGS_(__VA_ARGS__, RSEQ())

// 用法
static int a[NARGS(A,B,C) == 3 ? 1 : -1]; // 通過即為 3

在宏里“折疊”一棵小表達(dá)式樹

#define PLUS(a,b) ((a)+(b))
#define TIMES(a,b) ((a)*(b))

// FOLD(PLUS, 0, 1,2,3) => (((0+1)+2)+3)
#define FOLD(op, init, first, ...) \
  op(init, first) \
  IF(HAS_ARGS(__VA_ARGS__))( \
    OBSTRUCT()(DEFER(FOLD)()(op, /* init= */ op(init, first), __VA_ARGS__)) \
  , /* empty */)

到此這篇關(guān)于C語言遞歸宏的具體使用的文章就介紹到這了,更多相關(guān)C語言 遞歸宏內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++結(jié)構(gòu)體struct和類class區(qū)別詳解

    C++結(jié)構(gòu)體struct和類class區(qū)別詳解

    struct和class有什么區(qū)別?最本質(zhì)的一個區(qū)別就是默認(rèn)的訪問控制:默認(rèn)的繼承訪問權(quán)限,struct是public的,class是private的。
    2017-11-11
  • C++中使用mutable關(guān)鍵字的場景分析

    C++中使用mutable關(guān)鍵字的場景分析

    C++中的mutable關(guān)鍵字用于修飾類的成員變量,使其在const成員函數(shù)中可以被修改,它主要用于緩存、線程同步和調(diào)試等場景,以支持對象的邏輯常量性,在使用mutable時,應(yīng)確保其修改不會破壞對象的外部表現(xiàn)狀態(tài),本文介紹C++中使用mutable關(guān)鍵字的場景分析,感興趣的朋友一起看看吧
    2025-02-02
  • C++野指針的具體實現(xiàn)

    C++野指針的具體實現(xiàn)

    野指針就是指針指向的不是一個有效(合法)的地址,本文主要介紹了C++野指針的具體實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-03-03
  • 詳解C++編程中的條件判斷語句if-else與switch的用法

    詳解C++編程中的條件判斷語句if-else與switch的用法

    這篇文章主要介紹了C++編程中的條件判斷語句if-else與switch的用法,是C++入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2016-01-01
  • c++項目構(gòu)成從cmake使用基礎(chǔ)詳解

    c++項目構(gòu)成從cmake使用基礎(chǔ)詳解

    這篇文章主要為大家介紹了c++項目構(gòu)成,從cmake使用基礎(chǔ)開始為大家講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • C++課程設(shè)計之圖書館管理系統(tǒng)

    C++課程設(shè)計之圖書館管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++課程設(shè)計之圖書館管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 詳解C++ sort函數(shù)的cmp參數(shù)

    詳解C++ sort函數(shù)的cmp參數(shù)

    這篇文章主要介紹了C++ sort函數(shù)的cmp參數(shù),以升降排序個結(jié)構(gòu)體的排序展開的話題,感興趣的小伙伴可以參考下面文章內(nèi)容
    2021-09-09
  • C++中typeid實現(xiàn)原理詳解

    C++中typeid實現(xiàn)原理詳解

    這篇文章主要給大家介紹了關(guān)于C++中typeid實現(xiàn)原理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 使用C++11實現(xiàn)Android系統(tǒng)的Handler機制

    使用C++11實現(xiàn)Android系統(tǒng)的Handler機制

    這篇文章主要介紹了使用C++11實現(xiàn)Android系統(tǒng)的Handler機制,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • C語言編寫掃雷小程序

    C語言編寫掃雷小程序

    這篇文章主要為大家詳細(xì)介紹了C語言編寫掃雷小程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09

最新評論

中山市| 沐川县| 洪江市| 灵寿县| 眉山市| 阿城市| 壶关县| 清苑县| 桓仁| 淄博市| 郑州市| 海丰县| 湟中县| 兰西县| 辽阳县| 舟曲县| 万山特区| 崇义县| 石楼县| 永丰县| 屏山县| 江孜县| 多伦县| 通州市| 泗阳县| 金川县| 涿鹿县| 邮箱| 安远县| 西乌珠穆沁旗| 田阳县| 晴隆县| 体育| 灵山县| 景德镇市| 海伦市| 宝应县| 石门县| 鹤庆县| 海原县| 京山县|