跳转至

跳转表

指针数组

  • 是一个数组
  • 数组的每个元素:指针

eg:

int *a[5];

ps:数组指针:首先是一个指针,指针指向的是一个数组

int arr[10];
int (*p)[10]; //p指向元素大小为10的数组

函数指针

  • 是一个指针
  • 指向的是某个函数(即存储函数地址)

eg:

int (*p)(int, int);
  • 指针p指向函数参数列表为(int, int)的函数
  • 函数返回值为int

函数指针数组

综上:

int (*p[])(int, int) = {f1, f2, f3};
  • 是一个数组
  • 数组的每个元素存放的元素类型是函数地址(指向某个函数的指针)
  • 每个元素指向的函数的参数列表都是(int, int)
  • 每个元素指向的函数的返回值都是int


跳转表实现

  • 使用switch:但代码过于冗余
  • 定义一个函数指针数组,实现根据输入不同的参数调用某个特定的函数

C++不支持可变长数组,所以以下编码是不通过的:

example.cpp
#ifndef _EXAPLE_H_
#define _EXAPLE_H_

#include <inttypes.h>
#include <unordered_map>
#include <cstring>
#include <iostream>
using namespace std;

unordered_map<int, string> testmap = {
    {1, "test1"},
    {2, "test2"},
    {3, "test3"}};

struct project
{
    char *signame;
    uint32_t sigval;
};

class solveTest
{
public:
    solveTest() = default;
    const uint32_t getIdx(const string str);
    const string gettest(uint32_t idx, project *pro);
    void getSolve(const string str);
    // jump teble
    void(*funcArr[])() = {test1,
                          test2,
                          test3};

private:
    void test1() { cout << "this is test1." << endl; }
    void test2() { cout << "this is test2." << endl; }
    void test3() { cout << "this is test3." << endl; }
};

const uint32_t solveTest::getIdx(const string str)
{
    if (!str.size() || str.size() != 5)
    {
        cout << "input string error." << endl;
        return -1;
    }
    char *tmp = const_cast<char *>(str.c_str());

    return tmp[4] - '0';
}

void solveTest::getSolve(const string str)
{
    funcArr[getIdx(str)]();
}

const string solveTest::gettest(uint32_t idx, project *pro)
{
    string ret;
    if (!pro)
    {
        cout << "project is null." << endl;
    }
    else
    {
        if (testmap.find(idx) != testmap.end())
        {
            ret = testmap[idx];
        }
    }
    return ret;
}

#endif
main.cpp
#include "example.hpp"
#include <iostream>

int main(int argc, char** argv){
    solveTest st;
    std::cout<<"test1 get index: "<<st.getIdx("test1")<<std::endl;
    st.getSolve("test1");

    return 0;
}

C语言实现

example.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

typedef struct
{
    const char *signame;
    uint32_t sigval;
} project;

void test1()
{
    printf("this is test1.\n");
}

void test2()
{
    printf("this is test2.\n");
}

void test3()
{
    printf("this is test3.\n");
}

// jump table
void (*funcArr[])() = {test1, test2, test3};

void getTest(project *pro, const char *tn)
{
    if (pro == NULL || tn == NULL)
        return;

    pro->signame = tn;
    uint32_t i = 0;
    if (*(tn + 5) != '\0')
        return;
    const char* cmp = "test";
    if (strncmp(cmp, tn, 4) == 0)
    {
        funcArr[*(tn + 4) - '0' - 1]();
        return;
    }
    printf("input str error!\n");
}
main.c
#include <string.h>
#include "example.h"

int main(int argc, char **argv)
{
    project p;
    getTest(&p, "test1");
    printf("p->signame: %s\n", p.signame);

    getTest(&p, "test2");
    printf("p->signame: %s\n", p.signame);

    getTest(&p, "test3");
    printf("p->signame: %s\n", p.signame);

    return 0;
}
cmake_minimum_required(VERSION 3.10)
project(main)

set(CMAKE_C_FLAGS "-g")

include_directories("./example.h")
set(SOURCE_FILE main.c)
add_executable(${PROJECT_NAME} ${SOURCE_FILE})

运行结果:

zjp@zjp-Ubuntu:~/test/jump_table/c/build$ ./main 
this is test1.
p->signame: test1
this is test2.
p->signame: test2
this is test3.
p->signame: test3
zjp@zjp-Ubuntu:~/test/jump_table/c/build$