Массив таблиц переходов в C - PullRequest
0 голосов
/ 30 ноября 2018

Я пытаюсь оптимизировать доступ к некоторым таблицам переходов, которые я сделал, они выглядят следующим образом:

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);

Как вы, возможно, уже догадались, я изо всех сил пытаюсь выяснить, как построить эту таблицу.Я подумал, что это одна из двух вещей:

  1. Еще один простой массив указателей, поскольку даже таблица переходов сама по себе является просто массивом указателей.Следовательно, моя инициализация будет:

    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 ]

0 голосов
/ 30 ноября 2018

Вы можете обнаружить, что определение 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;
}
0 голосов
/ 30 ноября 2018

Просто добавьте *, как вы добавили [] при определении массива.

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), если вы не хотите, чтобы аргументы передавались в вашу функцию.

This:

const int* (*usart_peripheral_table[<number of jump tables])();

Это массив указателей на функции, которые принимают неопределенное количество аргументов и возвращают указатель на постоянное целое число.

This:

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)();
}
...