C中的跳转表数组
Array of jump tables in C
我正在尝试优化对我所做的一些跳转 table 的访问,它们如下:
int (*const usart_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[USART_READ_WRITE_CLEAR])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
如您所见,这些函数用于在硬件级别访问 usart 外设,并按 read/write/clear.
的顺序排列在 table 中
我想做的是再跳转 table 跳转 tables,这样我可以 运行 通过在启动时初始化所有 usart 的寄存器或者简单地改变如果需要,稍后可以注册一个。
即
<datatype> (*usart_peripheral_table[<number of jump tables>])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
这样我就可以将 table 公开给我的中间件层,这将有助于在不断变化的 HAL 中保持标准,而且我可以使用定义来索引这个 table 即
fn_ptr = usart_peripheral_table[CTRL_TABLE]
fn_ptr[WRITE](bitmask);
fn_ptr[READ](buffer);
正如您可能已经猜到的那样,我正在努力弄清楚如何构建这个 table。我认为这是两件事之一:
又一个简单的指针数组,因为即使是跳转table本身也只是一个指针数组。因此我的初始化是:
const int* (*usart_peripheral_table[<number of jump tables])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
但这似乎不起作用。然后我想:
指向指针的指针数组。所以我尝试了各种组合:
const int**(*usart_perip...
const int**(usart_perip...
const int** (*usart_peripheral_table[<number of jump tables])() =
{&usart_ctrl_table, &usart_frame_table[0], usart_trig_ctrl_table};
似乎没有任何效果。在将该变量分配给指针到指针数组之前,我是否需要将较低跳转 tables 的地址存储在另一个指针中?即
int* fn_ptr = usart_ctrl_table;
<dataytype>(*const usart_periph[<number>])() = {fn_ptr};
在此先致谢,如有任何帮助,我们将不胜感激。
MM25
编辑:
const int** (*const peripheral_table[1])() =
{&usart_ctrl_table[0]};
const int** (*const peripheral_table[1])() =
{usart_ctrl_table};
以上都给出了错误 "initialization from incomaptible pointer type",我尝试过的所有其他组合也是如此
只需添加一个 *
就像您在定义数组时添加 []
一样。
int zg_usartCtrlRead();
int zg_usartCtrlWrite();
int zg_usartCtrlClr();
int zg_usartFrameRead();
int zg_usartFrameWrite();
int zg_usartFrameClr();
int zg_usartTrigctrlRead();
int zg_usartTrigctrlWrite();
int zg_usartTrigctrlClr();
int (*const usart_ctrl_table[])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
int (* const * const usart_peripheral_table[])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
用法:
usart_peripheral_table[1][2](5, 1, 3, 5, 6);
顺便说一句,函数声明中的空参数列表 ()
表示未指定参数的数量和类型。如果您不想向函数传递任何参数,请执行 (void)
。
这个:
const int* (*usart_peripheral_table[<number of jump tables])();
是一个函数指针数组,它接受未指定数量的参数,return 是一个指向常量整数的指针。
这个:
const int** (*usart_peripheral_table[<number of jump tables])()
是一个函数指针数组,它接受未指定数量的参数和return一个指向常量整数的指针。
您也可以使用二维数组:
int (* const usart_peripheral_table_2d[][3])() = {
{
zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr,
}, {
zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr,
}, {
zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr,
},
};
但也许您想编写访问器函数,将 return 指向函数数组的指针。没有比这更简单的了!
#include <stddef.h>
int (*usart_ctrl_table_get(size_t idx))() {
return usart_ctrl_table[idx];
}
int (*usart_frame_table_get(size_t idx))() {
return usart_frame_table[idx];
}
int (*usart_trig_ctrl_table_get(size_t idx))() {
return usart_trig_ctrl_table[idx];
}
int (* const (* const usart_peripheral_table_indirect[])(size_t))() = {
usart_ctrl_table_get,
usart_frame_table_get,
usart_trig_ctrl_table_get,
};
用法示例:
int main() {
usart_peripheral_table_indirect[2](1)();
}
您可能会发现为您的函数指针定义一个 typedef
可以让您的代码更易于阅读和维护(尽管我也看到有人反对它):
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
uart_ctl_func uart_ctl_jump_table[][UART_RWC] = {
{ uart_read, uart_write, uart_clear },
{ uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_jump_table[0][1](); // Write.
uart_ctl_jump_table[1][0](); // Read.
uart_ctl_jump_table[1][2](); // Clear.
return EXIT_SUCCESS;
}
下一步可能是使跳转 table 成为 struct
,这样您最终会写成 Uart_ctl_table.frame.read()
,或者至少为常量定义一个 enum
.
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
typedef struct {
uart_ctl_func read;
uart_ctl_func write;
uart_ctl_func clear;
} uart_ctl_set_t;
typedef struct {
uart_ctl_set_t ctrl;
uart_ctl_set_t frame;
uart_ctl_set_t trig;
} uart_ctl_table_t;
const uart_ctl_table_t uart_ctl_table = {
.ctrl = { uart_read, uart_write, uart_clear },
.frame = { uart_read, uart_write, uart_clear },
.trig = { uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_table.ctrl.write(); // Write.
uart_ctl_table.frame.read(); // Read.
uart_ctl_table.trig.clear(); // Clear.
return EXIT_SUCCESS;
}
我正在尝试优化对我所做的一些跳转 table 的访问,它们如下:
int (*const usart_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[USART_READ_WRITE_CLEAR])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
如您所见,这些函数用于在硬件级别访问 usart 外设,并按 read/write/clear.
的顺序排列在 table 中我想做的是再跳转 table 跳转 tables,这样我可以 运行 通过在启动时初始化所有 usart 的寄存器或者简单地改变如果需要,稍后可以注册一个。
即
<datatype> (*usart_peripheral_table[<number of jump tables>])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
这样我就可以将 table 公开给我的中间件层,这将有助于在不断变化的 HAL 中保持标准,而且我可以使用定义来索引这个 table 即
fn_ptr = usart_peripheral_table[CTRL_TABLE]
fn_ptr[WRITE](bitmask);
fn_ptr[READ](buffer);
正如您可能已经猜到的那样,我正在努力弄清楚如何构建这个 table。我认为这是两件事之一:
又一个简单的指针数组,因为即使是跳转table本身也只是一个指针数组。因此我的初始化是:
const int* (*usart_peripheral_table[<number of jump tables])() = {usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
但这似乎不起作用。然后我想:
指向指针的指针数组。所以我尝试了各种组合:
const int**(*usart_perip... const int**(usart_perip... const int** (*usart_peripheral_table[<number of jump tables])() = {&usart_ctrl_table, &usart_frame_table[0], usart_trig_ctrl_table};
似乎没有任何效果。在将该变量分配给指针到指针数组之前,我是否需要将较低跳转 tables 的地址存储在另一个指针中?即
int* fn_ptr = usart_ctrl_table;
<dataytype>(*const usart_periph[<number>])() = {fn_ptr};
在此先致谢,如有任何帮助,我们将不胜感激。
MM25
编辑:
const int** (*const peripheral_table[1])() =
{&usart_ctrl_table[0]};
const int** (*const peripheral_table[1])() =
{usart_ctrl_table};
以上都给出了错误 "initialization from incomaptible pointer type",我尝试过的所有其他组合也是如此
只需添加一个 *
就像您在定义数组时添加 []
一样。
int zg_usartCtrlRead();
int zg_usartCtrlWrite();
int zg_usartCtrlClr();
int zg_usartFrameRead();
int zg_usartFrameWrite();
int zg_usartFrameClr();
int zg_usartTrigctrlRead();
int zg_usartTrigctrlWrite();
int zg_usartTrigctrlClr();
int (*const usart_ctrl_table[])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
int (* const * const usart_peripheral_table[])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
用法:
usart_peripheral_table[1][2](5, 1, 3, 5, 6);
顺便说一句,函数声明中的空参数列表 ()
表示未指定参数的数量和类型。如果您不想向函数传递任何参数,请执行 (void)
。
这个:
const int* (*usart_peripheral_table[<number of jump tables])();
是一个函数指针数组,它接受未指定数量的参数,return 是一个指向常量整数的指针。
这个:
const int** (*usart_peripheral_table[<number of jump tables])()
是一个函数指针数组,它接受未指定数量的参数和return一个指向常量整数的指针。
您也可以使用二维数组:
int (* const usart_peripheral_table_2d[][3])() = {
{
zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr,
}, {
zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr,
}, {
zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr,
},
};
但也许您想编写访问器函数,将 return 指向函数数组的指针。没有比这更简单的了!
#include <stddef.h>
int (*usart_ctrl_table_get(size_t idx))() {
return usart_ctrl_table[idx];
}
int (*usart_frame_table_get(size_t idx))() {
return usart_frame_table[idx];
}
int (*usart_trig_ctrl_table_get(size_t idx))() {
return usart_trig_ctrl_table[idx];
}
int (* const (* const usart_peripheral_table_indirect[])(size_t))() = {
usart_ctrl_table_get,
usart_frame_table_get,
usart_trig_ctrl_table_get,
};
用法示例:
int main() {
usart_peripheral_table_indirect[2](1)();
}
您可能会发现为您的函数指针定义一个 typedef
可以让您的代码更易于阅读和维护(尽管我也看到有人反对它):
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
uart_ctl_func uart_ctl_jump_table[][UART_RWC] = {
{ uart_read, uart_write, uart_clear },
{ uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_jump_table[0][1](); // Write.
uart_ctl_jump_table[1][0](); // Read.
uart_ctl_jump_table[1][2](); // Clear.
return EXIT_SUCCESS;
}
下一步可能是使跳转 table 成为 struct
,这样您最终会写成 Uart_ctl_table.frame.read()
,或者至少为常量定义一个 enum
.
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
typedef struct {
uart_ctl_func read;
uart_ctl_func write;
uart_ctl_func clear;
} uart_ctl_set_t;
typedef struct {
uart_ctl_set_t ctrl;
uart_ctl_set_t frame;
uart_ctl_set_t trig;
} uart_ctl_table_t;
const uart_ctl_table_t uart_ctl_table = {
.ctrl = { uart_read, uart_write, uart_clear },
.frame = { uart_read, uart_write, uart_clear },
.trig = { uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_table.ctrl.write(); // Write.
uart_ctl_table.frame.read(); // Read.
uart_ctl_table.trig.clear(); // Clear.
return EXIT_SUCCESS;
}