2012-03-29 3 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

"인덱스를 사용하면 함수 자체의 이름을 사용할 수 있습니다."찾고있는 것은 상위 레벨 언어 또는 해시 테이블 중 하나입니다. 해시 테이블은 string -> function pointer가 될 것입니다. – 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 - 이것은 OP가 요구하는 것과 매우 비슷합니다. 그것은 80 년대에 우리가 C++ 가상 기능을 정복했을 때 일반적인 기술 이었지만 PC에는 C 만있었습니다. – gbulmer