C语言实现反射
高级语言的反射机制,简单来说就是可以通过字符串型获取对应的类或者函数。
- 基础形式,c语言结构化编程基础实现
1)声明
typedef void (*callback)(void);
typedef struct {
const char *name;
callback fn;
}callback_t;
void f0();
void f1();
callback_t callbacks[] = {
{ "cmd0", f0},
{"cmd1", f1},
}
void f0()
{
}
void f1()
{
}
2)调用
void do_callback(const char *name)
{
size_t i;
for (i = 0; i < sizeof(callbacks) / sizeof(callbacks[0]); i++) {
if (!strcmp(callbacks[i].name, name)) {
return callbacks[i].fn();
}
}
}
这种方式的不便之处在于,当需要映射的函数因分散在不同文件时,每增加一个新的映射都需要修改这个数组,以及头文件。
2 利用自定义段
gcc支持通过使用__attribute__((section())),将函数、变量放到指定的数据段中。
也就是说,可以让编译器帮我们完成1中向数组添加成员的动作。
借助此机制,回调函数可以在任意文件申明,不需要修改其他文件。
自定义段的起始和结束地址,可以通过变量__start_SECTIONNAME和__stop_SECTIONNAME得到
例如通过__attribute__((section("ss"))定义自定义段,其开始地址为&__start_ss,结束地址为&__stop_ss
以实际代码示例:
文件a.c:
#define SEC __attribute__((__section__("ss"), aligned(sizeof(void*))))
void f1 (int a, int b)
{
printf("%s %d %d %d\n", __func__, __LINE__, a, b);
}
// 编译器会自动提供__start_ss,__stop_ss标志段ss的起止地址
extern size_t __start_ss;
extern size_t __stop_ss;
typedef struct {
void (*p)(int, int);
} node_t;
// 结构体变量a位于自定义段ss
SEC node_t a = {
.p = f1,
};
int main(int argc, char **argv)
{
int a = 0, b = 0;
node_t *p;
// 遍历段ss,执行node_t结构中的p指向的函数
for (p = &__start_ss; p < &__stop_ss;p++) {
p->p(a, b);
a+=1;b+=2;
}
}
文件b.c:
#include
#define SEC __attribute__((__section__("ss"), aligned(sizeof(void*))))
void ff(int a, int b)
{
printf("%s %d %d %d\n", __func__, __LINE__, a, b);
}
typedef struct {
void (*p)(int, int);
} node_t;
// 结构体变量m位于自定义段ss
SEC node_t m = {
.p = ff,
};
编译指令:
gcc a.c b.c
执行结果:
0x559ae9a88010 0x559ae9a88010 0x559ae9a88030
f1 8 0 0
0x559ae9a88028 0x559ae9a88010 0x559ae9a88030
ff 6 3 6