最近在Linux内核中看到一种指针数组的写法,实现了类似“键值对”的功能,代码非常精炼。
函数指针
首先回顾一下函数指针的定义方式:
int(*func)(int, int); // 定义
func = addr; // 赋值
int x = func(a, b); // 调用
也可以使用 typedef
:
typedef int(*Func)(int, int);
Func func; // 定义
func = addr; // 赋值
int x = func(a, b); // 调用
函数指针数组
那么,函数指针数组就是在函数指针的基础上改写,在变量后加[ ]
即可:
static int (*handle[]) (int, int);
如果这样写,也就比较容易看懂。
但高明之处在于,在声明数组的时候进行初始化:
static int (*reloc_handlers[]) (struct module *me, u32 *location, Elf_Addr v){
[R_RISCV_32] = apply_r_riscv_32_rela,
[R_RISCV_64] = apply_r_riscv_64_rela,
[R_RISCV_BRANCH] = apply_r_riscv_branch_rela,
[R_RISCV_JAL] = apply_r_riscv_jal_rela,
[R_RISCV_RVC_BRANCH] = apply_r_riscv_rcv_branch_rela,
[R_RISCV_RVC_JUMP] = apply_r_riscv_rvc_jump_rela,
[R_RISCV_PCREL_HI20] = apply_r_riscv_pcrel_hi20_rela,
[R_RISCV_PCREL_LO12_I] = apply_r_riscv_pcrel_lo12_i_rela,
[R_RISCV_PCREL_LO12_S] = apply_r_riscv_pcrel_lo12_s_rela,
[R_RISCV_HI20] = apply_r_riscv_hi20_rela,
[R_RISCV_LO12_I] = apply_r_riscv_lo12_i_rela,
[R_RISCV_LO12_S] = apply_r_riscv_lo12_s_rela,
[R_RISCV_GOT_HI20] = apply_r_riscv_got_hi20_rela,
[R_RISCV_CALL_PLT] = apply_r_riscv_call_plt_rela,
[R_RISCV_CALL] = apply_r_riscv_call_rela,
[R_RISCV_RELAX] = apply_r_riscv_relax_rela,
[R_RISCV_ALIGN] = apply_r_riscv_align_rela,
[R_RISCV_ADD32] = apply_r_riscv_add32_rela,
[R_RISCV_SUB32] = apply_r_riscv_sub32_rela,
};
其中 R_RISCV_*
为连续的从0开始的宏定义,作为标号,对每一个成员进行初始化。
这样在后续查表的时候,就可以通过宏直接定位到相应的 handler
函数:
handler = reloc_handlers[type];
handler(...);
真的是,学到了
数组初始化
最后,再来回顾一下数组初始化的几种方法吧~
https://en.cppreference.com/w/c/language/array_initialization
字符串数组
wchar_t wstr[4] = L"猫"; // holds L'猫', '\0', '\0', '\0'
char *str = "abc"; // holds 'a', 'b', 'c', '\0'
char str[] = "abc"; // holds 'a', 'b', 'c', '\0'
char str[3] = "abc"; // holds 'a', 'b', 'c'
// Character names can be associated with enumeration constants
// using arrays with designators:
enum { RED, GREEN, BLUE };
const char *color_name[] = {
[RED] = "red",
[GREEN] = "green",
[BLUE] = "blue",
};
一维数组
int x[] = {1, 2, 3}; // 省略元素个数: 1,2,3
int y[5] = {1, 2, 3}; // 固定元素个数: 1,2,3,0,0
int z[3] = {0}; // 统一初始化: 0,0,0
int n[5] = {[3] = 0, [0] = 1, 2, 3, 4}; // 单独初始化: 1,2,0,4,5
更灵活的初始化:
int a[MAX] = { 1, 3, 5, 7, 9, [MAX - 5] = 8, 6, 4, 2, 0};
// for MAX=6, array holds 1,8,6,4,2,0
// for MAX=13, array holds 1,3,5,7,9,0,0,0,8,6,4,2,0 ("sparse array")
多维数组
// The following five array declarations are the same
short q1[4][3][2] = {
{ 1 },
{ 2, 3 },
{ 4, 5, 6 }
};
short q2[4][3][2] = {1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 4, 5, 6};
short q3[4][3][2] = {
{
{ 1 },
},
{
{ 2, 3 },
},
{
{ 4, 5 },
{ 6 },
}
};
short q4[4][3][2] = {1, [1]=2, 3, [2]=4, 5, 6};
short q5[4][3][2] = {
{
{ 1, 0, },
{ 0, 0, },
{ 0, 0, },
},
{
{ 2, 3 },
{ 0, 0, },
{ 0, 0, },
},
{
{ 4, 5 },
{ 6, 0, },
{ 0, 0, },
},
{
{ 0, 0, },
{ 0, 0, },
{ 0, 0, },
},
};
版权声明:本文为Augurlee原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。