2016-02-16 2 views
-2

Каков наилучший способ вызова указанной функции на основе пользовательского ввода, кроме серии if и strcmp? Например:Таблица поиска функций с различными прототипами функций

p 2 2 -> call func_p(2, 2) 
a 8 -> call func_a(7) 
m  -> call func_m(void) 

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

+1

Определите все функции, чтобы они принимали один аргумент массива. – Barmar

+0

Это моя вторая мысль - заставить все функции принять 'char *' и вызвать определенную функцию на основе первого слова ввода пользователя. – user1042840

ответ

1

Определите все функции, чтобы они принимали один аргумент массива.

Комментарий от Barmar

Unifying все функции к тому же прототипу именно то, что один обычно делает в этом случае, хотя я бы с прототипом с двумя параметрами: Указатель на массив с реальным параметры, а также размер. Таким образом, не каждая функция должна самостоятельно разбивать/анализировать свои аргументы.

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

#include <stdio.h> 
#include <stdlib.h> 
#include <stdbool.h> 
#include <string.h> 

// a node in the abstract syntax tree. Either a 
// value or a call 
struct Ast { 
    bool isCall; 
    union { 
    int value; 
    struct { 
     char const * operator; 
     size_t countOperands; 
     struct Ast * operands; 
    } call; 
    }; 
}; 

// unified function type. Could've also passed an 
// int array, but then evaluate would've needed 
// a memory allocation, so ... 
typedef int (*Function)(struct Ast *, size_t); 


// implementation of + function. Sums the values of 
// parameters. (which are hopefully evaluated) 
int sum(struct Ast * parameters, size_t num) { 
    int result = 0; 
    while (num > 0) { 
    --num; 
    result += parameters [num]. value; 
    } 
    return result; 
} 

// implementation of ? function, ignores any 
// parameters and just asks for an integer. 
int ask (struct Ast * parameters, size_t num) { 
    int value; 
    scanf("%d", & value); 
    return value; 
} 

// poor man's lookup table 
static Function const functions [] = {sum, ask}; 
static char const * const function_names [] = {"+", "?"}; 

// poor man's lookup from above static arrays 
Function lookup (char const * name) { 
    size_t it = sizeof (functions)/sizeof (functions [0]); 
    while (it > 0) { 
    --it; 
    if (strcmp(name, function_names [it]) == 0) { 
     return functions [it]; 
    } 
    } 
    exit(1); 
} 

// evaluate an Ast. Normally one wouldn't return 
// an Ast node but rather some value_t (assuming 
// dynamic typing) 
// this function is also destructive on call Ast nodes, 
// in order to get around any memory management. 
// so be careful! 
struct Ast * evaluate (struct Ast * node) { 
    if (! node->isCall) { 
    // anything that's not a call is a value, thus 
    // self evaluating, return it unchanged! 
    return node; 
    } 
    // so it's a call. Get the associated function from 
    // the lookup table! 
    Function f = lookup(node->call.operator); 
    // unconditionally evaluate all operands of the call. 
    // thus no macros or conditionals, sorry! 
    size_t o; 
    for (o = 0; o < node->call.countOperands; ++o) { 
    // destructive! 
    node->call.operands[o] = *evaluate(&(node->call.operands[o])); 
    } 
    // use the call node to store the result value. 
    // this will blow up if any call node uses any 
    // allocated memory! 
    node->isCall = false; 
    // call the function with the evaluated operands and 
    // store the result 
    node->value = f(node->call.operands, node->call.countOperands); 
    return node; 
} 

int main() { 
    // I didn't want to write a parser, so here's a 
    // static Ast of (+ 21 10 (?)) 
    struct Ast nodes [] = { 
    {.isCall=false, .value=21}, 
    {.isCall=false, .value=10}, 
    {.isCall=true, .call = { 
     .operator="?", .countOperands=0}}, 
    {.isCall=true, .call = { 
     .operator="+", .countOperands=3, 
     .operands=nodes}}}; 
    struct Ast * result = evaluate(&(nodes [3])); 
    printf("(+ 21 10 (?)) => %d\n", result->value); 
    return 0; 
} 

Written and "tested" on ideone.

Другой подход будет использовать void * меченый с некоторой информацией о типе функции. Но довольно сложно передать фактические параметры для функций, закодированных таким образом, и он также плохо масштабируется.

Смежные вопросы