用不同的函数原型函数查找表 [英] Function lookup table with different function prototypes

查看:152
本文介绍了用不同的函数原型函数查找表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是调用基于用户输入指定的功能,除了从系列,如果最好的方式 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;
}

上ideone书面和测试。

一个不同的方法是使用一个无效* 标签的一些功能类型的信息。但它是相当困难的实际参数传递给EN codeD这样的功能,而且它也不会很好地扩展。

What is the best way to call a specified function based on user input except from series of if and strcmp? 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆