使用GNU C扩展实现C的反射
说明:此机制并非传统意义上的反射,仅为一种类似的实现
我最近在写一个 Sandbox,需要根据命令行参数选择对应的规则函数执行。如果硬编码,这是非常痛苦的,所以我在 Google 搜了一会,发现了如下的办法,相比硬编码要好许多。
什么是 GNU C 扩展
众所周知,编译器不只是在翻译,还有优化、错误检查等许多工作,所以就催生了许多编译属性标识的产生。
你翻阅许多开源项目源码的时候肯定会看到一堆 define 和下划线的东西,比如__attribute__、__builtin_expect等。这些标识都是在给编译器传递信息,告诉它需要做什么事情,从而使得编译工作可以根据需要灵活调整。
这些被称为 C Extensions,即 GNU C 扩展
__attribute__((section))
在如此之多的扩展之中,有一项__attribute__((section)),用于修饰变量
根据官网文档的说明:
Normally, the compiler places the objects it generates in sections like
dataandbss. Sometimes, however, you need additional sections, or you need certain particular variables to appear in special sections, for example to map to special hardware. Thesectionattribute specifies that a variable (or function) lives in a particular section.通常来说,编译器把生成的对象放在
bss、data这样的段。但是有时候你需要把对象放到一个特定的段中,比如特定的硬件映射。这个标识符将被修饰对象放置于
section段中
所以,你可以做到这样的事情:
1 | // 定义变量,并放置于test段 |
编译器会自动定义__start##section和__end##section两个变量,分别指向该段的头尾,你可以使用它们进行访问范围控制
另外还需要注意的:
Use the
sectionattribute with global variables and not local variables只能修饰全局变量,所以注意作用域!
实现反射机制
直接把成品摆出来,下面解释
1 |
|
1 | bakaft@BakaFT-PC:~/oj$ gcc section_test.c |
可以看到,这里根据我们定义的字符串,执行了对应的函数,也就达到了目的。
原理
1 |
根据刚才的知识,这个宏的结果就是把一个struct func放到了程序的·functions段
这个结构体存放了一个指向函数x的函数指针,和一个值为x的字符串。这样就可以在后面使用循环,遍历functions段,寻找到我们需要的函数了
参考
使用GNU C扩展实现C的反射