const
может быть полезно в некоторых случаях, когда мы используем данные для направления кода определенным образом. Например, вот шаблон, который я использую при написании конечных автоматов:
typedef enum { STATE1, STATE2, STATE3 } FsmState;
struct {
FsmState State;
int (*Callback)(void *Arg);
} const FsmCallbacks[] = {
{ STATE1, State1Callback },
{ STATE2, State2Callback },
{ STATE3, State3Callback }
};
int dispatch(FsmState State, void *Arg) {
int Index;
for(Index = 0; Index < sizeof(FsmCallbacks)/sizeof(FsmCallbacks[0]); Index++)
if(FsmCallbacks[Index].State == State)
return (*FsmCallbacks[Index].Callback)(Arg);
}
Это похоже на что-то вроде:
int dispatch(FsmState State, void *Arg) {
switch(State) {
case STATE1:
return State1Callback(Arg);
case STATE2:
return State2Callback(Arg);
case STATE3:
return State3Callback(Arg);
}
}
но мне легче поддерживать, особенно в тех случаях, когда с состояниями связано более сложное поведение. Например, если мы хотим иметь механизм прерывания, зависящий от состояния, мы изменим определение структуры на:
struct {
FsmState State;
int (*Callback)(void *Arg);
void (*Abort)(void *Arg);
} const FsmCallbacks[] = {...};
и мне не нужно изменять обе подпрограммы abort
и dispatch
для нового состояния. Я использую const
для предотвращения изменения таблицы во время выполнения.