Позволяет избежать большого 'переключатель' вызывать в главном цикле


Я пишу оболочку Unix на C, которая использует довольно большой переключатель в главном цикле.

Он используется для выполнения встроенной команды типа 'компакт' или 'справка'. Так получается, что он анализирует вводимые пользователем, и возвращает 'comand_t' структуры, " имя " первой входного слова.

Для того, чтобы переключиться на веревочке, я его перевести в int, прочитав эту инициализировать структуру:

built_in_commands my_commands[CMD_NBR] = { 
    {""     , EMPTY_CMD         , ""},
    {"cd"   , CD_CMD            , "change directory"},
    {"env"  , ENV_CMD           , "print enviroment. Can show single variable"},
    {"exit" , EXIT_CMD          , "exit from AGROS"},
    {"help" , HELP_CMD          , "print help"},
    {"?"    , SHORTHELP_CMD     , "print short help"}
};

Макросы, определенные в заголовочном файле:

#define EMPTY_CMD           0

#define CD_CMD              1
#define ENV_CMD             2
#define EXIT_CMD            3
#define HELP_CMD            4
#define SHORTHELP_CMD       5
#define SETENV_CMD          6
#define GETENV_CMD          7

#define OTHER_CMD           8

#define CMD_NBR             9

основной цикл программы-это:

while (AG_TRUE){

    /* Set the prompt */
    get_prompt(prompt, MAX_LINE_LEN, username);

    /* 
     * Read a line of input 
     * commandline should be deallocated with free() 
     */
    commandline = read_input (prompt); 

    parse_command (commandline, &cmd);

    switch (get_cmd_code (cmd.name)){ //returns an int 
        case EMPTY_CMD:
            break;

        case CD_CMD:
            change_directory (cmd.argv[1], ag_config.loglevel);
            break;

        case HELP_CMD:
            print_help(&ag_config, cmd.argv[1]);
            break;

        case SHORTHELP_CMD:
            print_help(&ag_config, "-s");
            break;

        case ENV_CMD:
            print_env (cmd.argv[1]);
            break;

        case EXIT_CMD:
            free (commandline);
            commandline = (char *)NULL;
            closelog ();
            return 0;

        case OTHER_CMD:
            fork_and_exec();
            break;
    }
}

Каждый раз, когда я добавить новые функции строение, интересно, если нет лучшего способа сделать это. Что бы это было? Как я могу динамически вызвать функцию?



336
4
c
задан 15 октября 2011 в 01:10 Источник Поделиться
Комментарии
2 ответа

В дополнение к @Уинстон ноты на указатели на функции.

Я бы не делал этого:

built_in_commands my_commands[CMD_NBR] = { 
/// ^^^^^^^ This makes mainting the code harder.
/// If you add commands you now need to modify the code
/// in multiple places.

Это легче сделать это таким образом:

built_in_commands my_commands[] = { 
/// ^^ By leaving it blank the compiler works out the size.

int const CMD_NBR = sizeof(my_commands)/sizeof(my_commands[0]);
/// Now the compiler works out your constant of the size of the array.
/// Note: This also works for empty arrays as sizeof()
/// is done at compile time and thus works even if
/// my_commands[0] is not technically valid at
/// run-time.

5
ответ дан 15 октября 2011 в 06:10 Источник Поделиться

Указатели на функции

Вы хотите использовать функцию указки: http://www.newty.de/fpt/fpt.html

typedef void (*Command)(char const* args);  // Modify as required
// But something like this
struct built_in_commands
{
char const* command;
// int commandID; // Remove this you don't need it.
char const* man;
Command function; // Add this: A pointer to a function
};

Тогда ваш выключатель будет:

parse_command (commandline, &cmd);
if (cmd != NULL)
{ (*cmd->function)(commandline); // Call the function associated with
} // command (assuming you find it in the list)

Другие Заметки:

В общем, все ваши функции будет иметь такую же сигнатуру, а затем передаваться внутри вашей структуры, а не количество. Затем можно назвать указатель функции от структуры и прочь вы идете.

        case EXIT_CMD:
free (commandline);
commandline = (char *)NULL;
closelog ();
return 0;

Это, кажется, единственное место, где вы бесплатно командной строки. Но выделять его каждый раз вы получаете команду. Это означает, что у вас есть утечка. Там на самом деле не так много в момент освобождения памяти здесь, потому что все это будет бесплатно, как только процесс завершается в любом случае.

5
ответ дан 15 октября 2011 в 02:10 Источник Поделиться