Массив таблиц переходов в C
Я пытаюсь оптимизировать доступ к некоторым таблицам переходов, которые я сделал, они заключаются в следующем:
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 на аппаратном уровне и расположены в таблице в порядке чтения / записи / очистки.
То, что я пытаюсь сделать, - это иметь другую таблицу переходов таблиц переходов, таким образом я могу либо выполнить инициализацию всех регистров usart при запуске, либо просто изменить один регистр позже, если это необходимо.
т.е.
<datatype> (*usart_peripheral_table[<number of jump tables>])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
Таким образом, я могу представить эту таблицу на уровне промежуточного программного обеспечения, что поможет поддерживать стандарт при изменении HAL, а также я могу использовать определение для индексации этой таблицы, т.е.
fn_ptr = usart_peripheral_table[CTRL_TABLE]
fn_ptr[WRITE](bitmask);
fn_ptr[READ](buffer);
Как вы, возможно, уже догадались, я пытаюсь выяснить, как построить эту таблицу. Я понял, что это одна из двух вещей:
Еще один простой массив указателей, так как даже сама таблица переходов - это просто массив указателей. Следовательно, моя инициализация будет:
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};
Ничто не похоже на работу. Нужно ли сохранять адрес таблиц нижних переходов в еще одном указателе, прежде чем присваивать эту переменную массиву указателей на указатели? т.е.
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};
Оба приведенных выше дают ошибку "инициализация из несовместимого типа указателя", как и все другие комбинации, которые я пробовал
2 ответа
Просто добавьте *
как ты добавил []
при определении массива.
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])();
Массив указателей на функции, которые принимают неопределенное количество аргументов и возвращают указатель на постоянное целое число.
Это:
const int** (*usart_peripheral_table[<number of jump tables])()
Массив указателей на функции, которые принимают неопределенное количество аргументов и возвращают указатель на указатель на постоянное целое число.
Вы также можете использовать 2D-массив:
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,
},
};
Но, возможно, вы захотите написать функции доступа, которые будут возвращать указатель на массив функций. Нет ничего проще!
#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;
}
Следующим шагом может быть сделать таблицу прыжков 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;
}