使用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
data
andbss
. Sometimes, however, you need additional sections, or you need certain particular variables to appear in special sections, for example to map to special hardware. Thesection
attribute specifies that a variable (or function) lives in a particular section.通常来说,编译器把生成的对象放在
bss
、data
这样的段。但是有时候你需要把对象放到一个特定的段中,比如特定的硬件映射。这个标识符将被修饰对象放置于
section
段中
所以,你可以做到这样的事情:
1 | // 定义变量,并放置于test段 |
编译器会自动定义__start##section
和__end##section
两个变量,分别指向该段的头尾,你可以使用它们进行访问范围控制
另外还需要注意的:
Use the
section
attribute 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的反射