2012-03-29 5 views
4

Просьба привести несколько примеров использования таблицы перехода. Я видел этот пример на википедии:примеры примеров перехода в 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()?

+1

«используя индекс, есть способ использовать имя самой функции». То, что вы ищете, - это язык более высокого уровня или хеш-таблица. Хэш-таблица будет указателем на строку ->. – Corbin

+3

Если вы хотите позвонить с именем самой функции, то зачем вам в первую очередь нужна таблица перехода? –

+0

Я действительно не читал ваш последний пример, и теперь, когда я только что сделал, я считаю, что @PavanManjunath имеет смысл. Что именно ты пытаешься сделать? Я предположил, что вы хотите взять char * и вызвать функцию, основанную на ней. Как и в PHP вы можете делать $ func = "strtolower"; echo $ func ('CORBIN') ;. – Corbin

ответ

5

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

например.

#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

Ну, это может * иметь смысл: если у вас есть разные экземпляры структуры, например, для реализации своего рода таблицы виртуальных функций. – Matthias

+0

Это уродливо. Идите с блоками. –

7

Вы можете создать 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... 
}; 

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

+0

+1 - Это очень близко к тому, что я думаю, о котором спрашивает ОП. Это была обычная техника в 80-х, когда мы жаждали виртуальных функций C++, но только на C на ПК. – gbulmer