Примеры таблиц переходов в C
Пожалуйста, дайте мне несколько примеров использования таблицы переходов. Я видел этот пример в Википедии:
#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 ответа
Конечно, но вы должны объявить их как указатели на функции и инициализировать их в первую очередь. Хотя это побеждает цель таблицы переходов, если вам нужно указать имя функции.
например
#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;
}
Вы, конечно, можете создать 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...
};
Затем некоторые высокоуровневые функции могут получать одно из них и открывать / закрывать / читать / записывать какое-либо устройство без необходимости знать точную идентификацию задействованного устройства. Конечно, для реальной ОС это немного сложнее, чем это, но общая идея (или, по крайней мере, может быть) довольно похожа.
Вы можете использовать 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