C语言以指针数组的方式实现map

最近在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版权协议,转载请附上原文出处链接和本声明。