Skip to content

表驱动法

字数: 0 字 阅读时间: 0 分钟

参照:表驱动法 | cchroot's blog

表驱动法可以简化判断逻辑,并且速度快,易于维护。

表驱动法的核心是表,所以也叫查表法。

举个例子,我们虽然可以通过泰勒展开计算 sin 1 这类非特殊角度的三角函数,但显然非常费事费力。但如果我们事先将 0 ~ 90 度的所有三角函数值写在一张纸上,那么得到 sin 1 的值就非常简单,直接查表就可以了。ARM DSP 库的三角函数就是用这个方法实现的。

再举个例子,假如我有一个遥控器,有 6 个按键,编号 KEY0 ~ KEY5 ,对应数字 0~5,每个按键对应不同的功能,而且更复杂的是 KEY1, KEY2, KEY3 还作为模式切换,不同模式下某些按键的功能还不一样。假设功能表是下面的:

Keymode1mode2mode3
KEY0shutdownshutdownshutdown
KEY1switch_mode1switch_mode1switch_mode1
KEY2switch_mode2switch_mode2switch_mode2
KEY3switch_mode3switch_mode3switch_mode3
KEY4Play MusicPlay RadioIncrease volume
KEY5Stop MusicStop RadioDecrease volume

假如不用表驱动,就用 if-else, switch-case ,那么代码将会是这样:

C
void key_scan() {
    // scan the key ...
    switch (key) {
        case KEY0: {
            shutdown();
        } break;

        case KEY1: {
            mode = 1;
        } break;

        case KEY2: {
            mode = 2;
        } break;

        case KEY3: {
            mode = 3;
        } break;

        case KEY4: {
            if (mode == 1) {
                play_music();
            } else if (mode == 2) {
                play_radio();
            } else if (mode == 3) {
                increase_volume();
            }
        } break;

        case KEY5: {
            if (mode == 1) {
                stop_music();
            } else if (mode == 2) {
                stop_radio();
            } else if (mode == 3) {
                decrease_volume();
            }
        } break;

        default: {
        } break;
    }
}

虽然用了 switch-case ,看着也不是太复杂,假如有非常多的按键,这里的判断逻辑将会变得非常复杂。可以用数组 + 函数指针来简化代码:

C
void (*key_callback)(int /* key */)[5] = {shutdown,    switch_mode, switch_mode,
                                          switch_mode, play_music,  stop_music};

void switch_mode(int key) {
    if (key == KEY1) {
        key_callback[KEY4] = play_music;
        key_callback[KEY5] = stop_music;
    } else if (key == KEY2) {
        key_callback[KEY4] = play_radio;
        key_callback[KEY5] = stop_radio;
    } else if (key == KEY3) {
        key_callback[KEY4] = increase_volume;
        key_callback[KEY5] = decrease_volume;
    }
}

void key_scan() {
    // scan the key ...
    key_callback[key_press](key_press);
}

如果我们要切换模式,只需要修改表中的函数指针就可以了,不需要多余的判断,而且扩展非常方便。

如果你对函数指针不熟悉,请复习 C 语言基础。

如果使用 Python,那么用字典就可以了,非常方便。

其他应用参照上面的链接。

Powered by VitePress, deployed by Github & Vercel.