c systems notebook

Dynamische Sprungtabelle

Compiler erzeugen für dichte switch-Anweisungen oft automatisch Sprungtabellen. Eine explizite Implementierung wird interessant, wenn die Einträge zur Laufzeit geändert oder erweitert werden sollen. Ohne const-Qualifizierung lässt sich die Tabelle anpassen, etwa um in Plugin-Systemen neue Funktionen dynamisch zu registrieren. So kann ein Programm sein Verhalten ändern, ohne neu kompiliert zu werden. Dies ist nützlich für konfigurierbare Systeme, bei denen verschiedene Module eigene Implementierungen für bestimmte Aktionen bereitstellen. Die Grundstruktur bleibt dabei unverändert, nur die Funktionszeiger in der Tabelle werden ausgetauscht.

Ergänzen wir unser Programm mit den Sprungtabellen, um eine neue Funktion set_action():

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

typedef void (*Action)();
typedef enum { ACT_START, ACT_STOP, ACT_COUNT } ActionKind;

// Aktionen (Default)
static void action_start()    { puts("System gestartet."); }
static void action_stop()     { puts("System gestoppt."); }

// Alternative Stop-Variante
static void action_stop_alt() { puts("System gestoppt, Variante 2."); }

// Dynamische Sprungtabelle (zur Laufzeit änderbar)
static Action ACTIONS[ACT_COUNT] = {
    action_start,
    action_stop
};

static Action select_action(ActionKind kind) {
    return (kind >= 0 && kind < ACT_COUNT) ? ACTIONS[kind] : nullptr;
}

static bool exec_action(ActionKind kind) {
    Action fn = select_action(kind);
    if (fn) fn();
    return fn != nullptr;
}

// Registriert/ersetzt die Funktion für eine Aktion; true bei Erfolg
static bool set_action(ActionKind kind, Action fn) {
    if (kind < 0 || kind >= ACT_COUNT) return false;
    ACTIONS[kind] = fn; // fn darf nullptr sein, um zu ›deaktivieren‹
    return true;
}

int main() {
    exec_action(ACT_START);               // Default

    set_action(ACT_STOP, action_stop_alt); // neue Stop-Variante setzen
    exec_action(ACT_STOP);                // nutzt die neue Funktion
}

Die Rückgabe von bool in set_action() erlaubt es dem Aufrufer, zu prüfen, ob die Registrierung erfolgreich war. Ein ungültiger Index führt dazu, dass die Funktion false zurückgibt, ohne das Array zu verändern.

Die Technik hat jedoch Grenzen. Wenn die Anzahl der Aktionen zur Compilezeit unbekannt ist oder zur Laufzeit stark variiert, reicht ein statisches Array nicht aus. In solchen Fällen muss man auf dynamische Datenstrukturen zurückgreifen.