用不同的函数原型函数查找表 [英] Function lookup table with different function prototypes
问题描述
什么是调用基于用户输入指定的功能,除了从系列,如果最好的方式
和 STRCMP
?例如:
P 2 2 - >调用func_p(2,2)
8 - >调用func_a(7)
米 - >电话func_m(无效)
我知道它的轻松优雅,使由函数指针与原型相同的查找表,但如何对不同的原型?我想到了一个原型使用 ...
,但我不知道这是否是一个很好的解决方案。
定义的所有功能,使他们采取单一的阵列参数。
从Barmar注释
块引用>统一到同一个原型的所有功能也正是一般人不会在这种情况下,虽然我用的原型去与两个参数:一个指向与实际参数数组以及它的大小。这样,不是每一个功能都有分裂/分析自身的参数。
我真的很喜欢这样的东西,所以我做了一个简短的演示。我提出这个我的手机,所以这是一个有点粗糙,而且需要一些改进,如果在野外(内存管理和错误检测为例)使用。在这里,它是:
的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&stdbool.h GT;
#包括LT&;&string.h中GT;//在抽象句法树中的节点。无论是
//值或电话
结构助攻{
布尔isCall;
工会{
int值;
结构{
字符常量*运营商;
为size_t countOperands;
结构助攻*操作数;
}调用;
};
};//统一的函数类型。也已经通过了一个
// int数组,但然后评估会一直需要
//内存分配,所以...
的typedef INT(*功能)(结构助攻*,为size_t);
//执行+的功能。和的值
//参数。 (这是希望评估)
INT总和(结构助攻*参数,为size_t NUM){
INT结果为0;
而(NUM大于0){
--num;
结果+ =参数[NUM]。值;
}
返回结果;
}// 实施 ?功能,忽略任何
//参数,只是要求一个整数。
INT问(结构助攻*参数,为size_t NUM){
int值;
scanf函数(%d个,&安培;值);
返回值;
}//穷人的查找表
静态函数const函数[] = {总和,问};
静态字符常量* const的function_names [] = {+,?};//穷人的静态数组上面查找
功能查找(字符常量*名字){
size_t型它= sizeof的(函数)/的sizeof(函数[0]);
而(它大于0){
- 它;
如果(STRCMP(姓名,function_names [它])== 0){
回归函数[它]
}
}
出口(1);
}//计算一个助攻。通常我们不会再回来
//一个AST节点,而是一些value_t(假设
//动态类型)
//这个功能也是随叫随到AST结破坏性的,
//为了避开任何内存管理。
//所以一定要小心!
结构助攻*评估(结构助攻*节点){
如果(与于节点GT;!isCall){
//什么,这不是一个呼叫是一个值,从而
//自我评估,原样返回!
返回节点;
}
//所以它是一个电话。获得从相关的功能
//查找表!
函数f =查找(&于节点GT; call.operator);
//无条件评估调用的所有操作数。
//因此没有宏或条件句,对不起!
为size_t O;
对于(O = 0; O<&于节点GT; call.countOperands ++ O){
//破坏力!
与于节点GT; call.operands [O] = *评估(及(或于节点GT; call.operands [O]));
}
//使用调用节点存储结果值。
//这将炸毁,如果任何调用节点使用任何
//分配内存!
与于节点GT; isCall = FALSE;
//调用该函数的计算和操作数
//存储结果
与于节点GT;值= f(与于节点GT; call.operands,及于节点GT; call.countOperands);
返回节点;
}诠释主(){
//我不想写一个解析器,所以这里是一个
//静态AST(+ 21 10(?))
结构AST结[] = {
{.isCall =假,.value的= 21},
{.isCall =假,.value的= 10},
{.isCall = TRUE,.CALL = {
.operator =?,.countOperands = 0}},
{.isCall = TRUE,.CALL = {
.operator =+,.countOperands = 3,
.operands =节点}}};
结构阿斯特*结果=评估(及(节点[3]));
的printf((+ 21 10())=>%d个\\ N,result->值);
返回0;
}一个不同的方法是使用一个
无效*
标签的一些功能类型的信息。但它是相当困难的实际参数传递给EN codeD这样的功能,而且它也不会很好地扩展。What is the best way to call a specified function based on user input except from series of
if
andstrcmp
? For example:p 2 2 -> call func_p(2, 2) a 8 -> call func_a(7) m -> call func_m(void)
I know it's easy and elegant to make a lookup table consisting of function pointers with the same prototype but how about different prototypes? I thought about using
...
in a prototype but I don't know if it's a good solution.解决方案Define all the functions so they take a single array argument.
Comment from Barmar
Unifying all functions to the same prototype is exactly what one normally does in this case, though I'd go with a prototype with two parameters: A pointer to an array with the real parameters as well as it's size. That way not every function has to split/parse its arguments on its own.
I really like stuff like this, so I made a short demo. I made this on my mobile, so it's a bit rough and would need some improvements if used in the wild (memory management and error detection for example). Here it is:
#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.
A different approach would be to use a
void *
tagged with some function type information. But it's rather difficult to pass the actual parameters to functions encoded like that, and it also doesn't scale well.这篇关于用不同的函数原型函数查找表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!