примеры таблиц переходов в C - PullRequest
5 голосов
/ 29 марта 2012

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

#include <stdio.h>
#include <stdlib.h>

typedef void (*Handler)(void);    /* A pointer to a handler function */



/* The functions */
void func3 (void) { printf( "3\n" ); }
void func2 (void) { printf( "2\n" ); }
void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }



Handler jump_table[4] = {func0, func1, func2, func3};



int main (int argc, char **argv) {
    int value;

    /* Convert first argument to 0-3 integer (Hash) */
    value = atoi(argv[1]) % 4;
    if (value < 0) {
        value *= -1;
    }

    /* Call appropriate function (func0 thru func3) */
    jump_table[value]();
}

Но мне было интересно, есть ли альтернативный способ вызова функции вместо использования индекса, как показано, в приведенном выше случае это jump_table[value]();

Чего я хочу добиться, так это вместо того, чтобы использовать индекс, есть способ использовать имя самой функции.

Например, скажем, у нас есть все указатели функций в структуре.

typedef struct _funcptrs
{
  void func1();
  void func2();
} funcptrs;

и теперь, когда я хочу вызвать функцию, могу ли я сделать что-то вроде funcptrs.func1()?

Ответы [ 3 ]

9 голосов
/ 30 марта 2012

Вы, безусловно, можете создать struct, содержащий указатели на функции.Для этого есть даже веские причины.

В качестве одного примера рассмотрим интерфейс между операционной системой и драйвером устройства.Упрощенно, это может выглядеть примерно так:

struct device { 
    int (*open)(unsigned mode);
    int (*close)(void);
    int (*read)(void *buffer, size_t size);
    int (*write)(void *buffer, size_t size);
};

Затем отдельный драйвер устройства создаст структуру этого типа и инициализирует отдельные указатели для ссылки на функции, относящиеся к конкретному устройству:

struct device serial_port = { 
    open_serial,
    close_serial,
    read_serial,
    write_serial
};

struct device ethernet_adapter = { 
    open_net,
    close_net,
    read_net,
    write_net
};

struct device keyboard = { 
    open_keyboard,
    close_keyboard,
    read_keyboard,
    NULL  // we'll assume no writing to the keyboard...
};

Тогда некоторые высокоуровневые функции могут получить одно из них и открыть / закрыть / прочитать / записать какое-либо устройство без необходимости знать точную идентификацию задействованного устройства.Конечно, для реальной ОС она становится немного более сложной, чем эта, но общая идея (или, по крайней мере, может быть) довольно похожа.

5 голосов
/ 29 марта 2012

Конечно, но вам нужно объявить их как указатели на функции и сначала инициализировать их.Хотя это отрицает цель таблицы переходов, если вам нужно прописать имя функции.

например,

#include <stdio.h>

void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }

typedef struct
{
  void (*func0)(void);
  void (*func1)(void);
}  funcptrs;

int main(int argc, char *argv[])
{
   funcptrs funcs = { func0, func1 };
   funcs.func1();
   return 0;
}

Если вам нужно вызвать функцию, указав имя функции какстрока, вам нужно создать отображение между именем функции и указателем на функцию, затем найти в таблице эту функцию и вызвать ее.

#include <stdio.h>
#include <string.h>

void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }

#define DEFUN(name) { #name, name }

typedef struct
{
  const char *name;
  void (*func)(void);
}  funcptrs;

void call(funcptrs *ptrs, const char *name)
{
    int i;
    for(i = 0; ptrs[i].name; i++) {
      if(strcmp(ptrs[i].name, name) == 0) {
           ptrs[i].func();
           break;
       }
    }
}
int main(int argc, char *argv[])
{
   funcptrs funcs[] = {DEFUN(func0), DEFUN(func1), {NULL,NULL}};
   call(funcs, "func0");
   return 0;
}
0 голосов
/ 07 июля 2018

Вы можете использовать enum для представления индексов вашего массива и дать им значимые имена для вас.

#include <stdio.h>
#include <stdlib.h>

typedef void (*Handler)(void);    /* A pointer to a handler function */

/* The functions */
void func3 (void) { printf( "3\n" ); }
void func2 (void) { printf( "2\n" ); }
void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }

enum{
    FUNC0,
    FUNC1,
    FUNC2,
    FUNC3
};

Handler jump_table[4] = {func0, func1, func2, func3};

int main (int argc, char **argv) {
    /* Call appropriate function (func0 thru func3) */
    jump_table[FUNC0]();
    jump_table[FUNC1]();
    jump_table[FUNC2]();
    jump_table[FUNC3]();
    return 0;
}

Это выведет

0
1
2
3
...