ARM Cortex-A72平台下自引用宏的终止条件实现与递归代码生成器问题
ARM Cortex-A72平台下自引用宏的终止条件实现与递归代码生成器问题
我来帮你解决这个递归宏的棘手问题!首先得明确你遇到的核心卡点:C预处理器有个硬性规则——宏展开时如果直接引用自身,会被标记为「已展开过」,不会再触发递归调用,所以你之前直接在CHILD宏里写CHILD(pName,__VA_ARGS__)是完全无效的。
要绕开这个限制,我们可以把递归逻辑拆分成终止宏、递归处理宏、分发宏三部分,用两层宏间接调用的方式规避自引用问题,同时通过参数数量自动判断终止时机,完全不需要依赖带固定迭代次数的FOR_EACH宏。下面是具体的可运行实现方案:
完整代码实现
#include <cstdint> // 1. 递归终止宏:当没有剩余参数时触发,什么都不做 #define CHILD_REC_END() // 2. 递归处理核心:每次处理一个子项的参数,然后间接触发递归处理剩余参数 #define CHILD_REC_HELPER(pName, cName, start, N, ...) \ struct cName##_t { \ int test; \ }; \ cName##_t cName; \ CHILD_REC(pName, __VA_ARGS__) // 间接递归,通过CHILD_REC触发而非直接调用自身 // 3. 分发宏:根据剩余参数数量选择继续递归还是终止 // 原理:如果剩余参数>=3个(对应一个子项的cName/start/N),就选CHILD_REC_HELPER;否则选CHILD_REC_END #define _CHILD_REC_DISPATCH(_1, _2, _3, MACRO, ...) MACRO // 4. 对外暴露的递归入口宏:间接调用分发宏,绕开自引用限制 #define CHILD_REC(pName, ...) \ _CHILD_REC_DISPATCH(__VA_ARGS__, CHILD_REC_HELPER, CHILD_REC_END)(pName, __VA_ARGS__) // 5. 父类定义宏:调用递归宏生成所有子项 #define PARENT(R, ...) \ struct R { \ R() = default; \ CHILD_REC(R, __VA_ARGS__) \ }; // 测试代码 PARENT(ParentA, ChildA, 0, 64); PARENT(ParentB, ChildA, 32, 1, ChildB, 0, 1); int main() { return ParentB().ChildA.test; // 可以正常访问,编译通过 }
方案生效的核心逻辑
绕开自引用限制
CHILD_REC_HELPER里没有直接调用自身,而是调用CHILD_REC这个中间宏,预处理器会把CHILD_REC当成全新的宏调用,不会触发「自引用忽略」的规则。自动终止递归
_CHILD_REC_DISPATCH利用预处理器的可变参数展开特性:当剩余参数不足3个(也就是没有完整的子项参数时),会自动匹配到CHILD_REC_END空宏,递归流程自动停止。完全匹配需求
预处理器展开后生成的代码和你原来的非递归版本完全一致,每个父类结构体里都会生成对应的子项结构体和成员变量,完全满足你对寄存器位域代码生成的需求。
展开效果验证
以PARENT(ParentB, ChildA,32,1, ChildB,0,1)为例,预处理器最终会展开为:
struct ParentB { ParentB() = default; struct ChildA_t { int test; }; ChildA_t ChildA; struct ChildB_t { int test; }; ChildB_t ChildB; };
完全符合你的预期,不会出现任何类型说明符错误。
内容来源于stack exchange
相关产品推荐
相关产品推荐

