如何在C/C++中用宏或模板生成带迭代编号的函数名?
结论先行
你的判断是正确的:普通运行时循环的迭代值无法传递给预处理器做标记拼接,因为预处理阶段执行在编译、运行阶段之前,运行时变量的值对预处理器完全不可见,因此直接用「简单宏+运行时循环」的方案确实走不通。
方案1:X宏(X Macro)方案(C/C++通用,无版本要求)
这是处理这类批量重复代码最常用的预处理方案,只需要维护一份中断号列表,就能自动生成所有声明和注册代码,全程没有重复逻辑:
- 先定义统一的中断列表宏:
// 所有需要注册的中断号都在这里加,后续不需要改其他代码 #define ISR_LIST \ ISR_ENTRY(0) \ ISR_ENTRY(1) \ ISR_ENTRY(2) \ ISR_ENTRY(3) \ // 按需加更多
- 生成所有
extern "C"声明:
#define ISR_ENTRY(n) extern "C" void interrupt_handler_##n(); ISR_LIST #undef ISR_ENTRY
- 生成批量注册逻辑:
void func() { #define ISR_ENTRY(n) setup_isr(n, interrupt_handler_##n); ISR_LIST #undef ISR_ENTRY }
如果后续要新增中断,只需要在ISR_LIST里加一行ISR_ENTRY(xxx)即可,不需要修改其他位置的代码。
方案2:C模板方案(C11及以上可用)
如果你的项目可以用现代C++特性,可以结合编译期序列实现批量注册,类型安全性更高,也方便加额外的编译期校验逻辑:
- 先做一个编译期的中断处理函数数组(可以结合上面的X宏生成数组内容,避免重复手写):
// 也可以用X宏生成这个数组的初始化列表,避免手写 constexpr void (*isr_handlers[])() = { interrupt_handler_0, interrupt_handler_1, interrupt_handler_2, // 更多handler };
- 用
std::index_sequence做编译期展开:
#include <utility> template <std::size_t... Is> void batch_setup_isr(std::index_sequence<Is...>) { // C++17及以上用折叠表达式,C++11可以用模板递归实现展开 (setup_isr(Is, isr_handlers[Is]), ...); } void func() { // 比如要注册0~19共20个中断,直接传入对应长度的index_sequence即可 batch_setup_isr(std::make_index_sequence<20>()); }
如果是C++11版本不支持折叠表达式,把batch_setup_isr改成模板递归的写法即可,逻辑是完全一致的。
内容的提问来源于stack exchange,提问作者Xcode23
相关产品推荐
相关产品推荐

