添加两个代表不同类型的结构

时间:2017-06-30 13:32:20

标签: c struct interpreter

我有一个像这样的结构:

typedef enum any_type{
    ANY_TYPE_CHAR,
    ANY_TYPE_UCHAR,
    ANY_TYPE_SHORT,
    ANY_TYPE_USHORT,
    ANY_TYPE_INT,
    ANY_TYPE_UINT,
    ANY_TYPE_LONG,
    ANY_TYPE_ULONG,
    ANY_TYPE_FLOAT,
    ANY_TYPE_DOUBLE,
} any_type;

typedef struct any{
    any_type type;
    union{
        char as_char;
        unsigned char as_uchar;
        short as_short;
        unsigned short as_ushort;
        int as_int;
        unsigned int as_uint;
        long as_long;
        unsigned long as_ulong;
        float as_float;
        double as_double;
    };
} any;

表示一个变量,它是指定的类型之一。这些结构有四种可能的操作,即加法,减法,乘法和除法。

我的问题是,是否有一种有效的方法对它们进行这些操作而不为每个案例做很多if语句?这会导致4 * 10 * 10 = 400 if / else if语句单独进行这四项操作,这当然效率不高!

我的代码位于C

提前致谢。

4 个答案:

答案 0 :(得分:3)

这将需要大量代码,因为combinatorial explosion是问题的一部分。

使用表驱动方法:定义两个表,一个用于在类型之间进行转换,另一个用于对它们执行操作。

对于转换,请创建一个函数指针类型

 void mapwidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    painter.drawPixmap(int x, int y, int w, int h, pixMap);
}

并在typedef any (*convert_any)(any val, any_type target); 上创建一个转换表:

convert_any conversion [] = {     convert_char,     convert_uchar,     convert_short,     ... };

对于每种类型都有这样的实现(你需要其中的十种):

any_type

对于操作,请创建另一个函数指针类型:

static any convert_char(any val, any_type target) {
    any res = { .type = target };
    switch (target) {
        case ANY_TYPE_CHAR: res.as_char = val.as_char; break;
        case ANY_TYPE_INT: res.as_int = (int)val.as_char; break;
        ...
    }
    return res;
}

您需要制作一个包含此类指针的3D数组 - 每个操作三次一个,左操作数的类型以及右操作数的类型。

实现看起来像这样:

typedef any (*operation_any)(any left, any right);

将有四十个这样的实现 - 每个结果类型和操作对一个。 3D表将包含400个条目,具体取决于操作需要生成的结果类型。调用将查找3D数组,查找static any add_int(any left, any right) { any lhs = conversion[left.type](left, ANY_TYPE_INT); any rhs = conversion[right.type](right, ANY_TYPE_INT); any res {.type = ANY_TYPE_INT, .as_int = lhs.as_int + rhs.as_int}; return res; } static any add_double(any left, any right) { any lhs = conversion[left.type](left, ANY_TYPE_DOUBLE); any rhs = conversion[right.type](right, ANY_TYPE_DOUBLE); any res {.type = ANY_TYPE_DOUBLE, .as_double = lhs.as_double + rhs.as_double }; return res; } 指针,传递两个参数,并获得如下结果:

operation_any

答案 1 :(得分:3)

为了避免组合噩梦,请考虑有3组类型,无符号整数有符号整数浮点

目标是确定操作要使用的3个组中的哪个组。然后获取每个类型和目标组的操作数值。根据该组进行数学计算。然后按组和最高排名类型保存。

对于10种类型中的每种类型,创建10个函数来获取数据并返回最宽的无符号整数。另外10个用于有符号整数,最后10个用于浮点

对于10种类型的每种类型,执行相同操作以创建设置数据的功能。到目前为止60个小功能。

要访问正确的功能,请使用函数中的表查找。另外3个获取功能,还有3个用于设置。

最后是一个示例添加功能。它寻找最高排名类型,并根据3组之一获取/添加/设置。

现在为-,/,*添加3个函数。总共约60 + 6 + 4个功能。

奖励:要添加像%这样的新功能,只需要再写一个函数。

#include<assert.h>

typedef enum any_type{
    // Insure these are in rank order
    // ANY_TYPE_CHAR left out for now
    ANY_TYPE_SCHAR,
    ANY_TYPE_UCHAR,
    ANY_TYPE_SHORT,
    ANY_TYPE_USHORT,
    ANY_TYPE_INT,
    ANY_TYPE_UINT,
    ANY_TYPE_LONG,
    ANY_TYPE_ULONG,
    ANY_TYPE_FLOAT,
    ANY_TYPE_DOUBLE,
    ANY_TYPE_N,
} any_type;

typedef struct any{
    any_type type;
    union{
        signed char as_schar;
        unsigned char as_uchar;
        short as_short;
        unsigned short as_ushort;
        int as_int;
        unsigned int as_uint;
        long as_long;
        unsigned long as_ulong;
        float as_float;
        double as_double;
    };
} any;

/////////////////////////////////////
unsigned long any_uget_schar(const any *x) {
  return (unsigned long) x->as_schar;
}
unsigned long any_uget_uchar(const any *x) {
  return x->as_uchar;
}
/* 8 more */

unsigned long any_get_unsigned(const any *x) {
  static unsigned long (*uget[ANY_TYPE_N])(const any *x) = {
    any_uget_schar, any_uget_uchar, /* 8 others */ };
  assert(x->type <  ANY_TYPE_N);
  return (uget[x->type])(x);
}

/////////////////////////////////////
signed long any_sget_schar(const any *x) {
  return x->as_schar;
}
signed long any_sget_uchar(const any *x) {
  return x->as_uchar;
}
/* 8 more */

signed long any_get_signed(const any *x) {
  static signed long (*sget[ANY_TYPE_N])(const any *x) = {
      any_sget_schar, any_sget_uchar, /* 8 others */ };
  assert(x->type <  ANY_TYPE_N);
  return sget[x->type](x);
}
/////////////////////////////////////

double any_get_fp(const any *x); // similar for floating point

/////////////////////////////////////

void any_uset_schar(any *x, unsigned long y) {
  x->as_schar = (signed char) y;
}

void any_uset_uchar(any *x, unsigned long y) {
  x->as_uchar = (unsigned char) y;
}

/* 8 more */

void any_set_unsigned(any *x, unsigned long y) {
  static void (*uset[ANY_TYPE_N])(any *x, unsigned long y) = {
    any_uset_schar, any_uset_uchar, /* 8 others */ };
  assert(x->type <  ANY_TYPE_N);
  uset[x->type](x,y);
}

/* 10 more for any_sset_... */

/* 10 more for any_fset_... */

///////////////////////////////////////////////

static const char classify[] = "susususuff";


any any_get_add(any a, any b) {
  any sum;
  sum.type = max(a.type, b.type);
  assert(sum.type <  ANY_TYPE_N);
  switch (classify[sum.type]) {
    case 's':
      any_set_signed(&sum, any_get_signed(&a) + any_get_signed(&b));
      break;
    case 'u':
      any_set_unsigned(&sum, any_get_unsigned(&a) + any_get_unsigned(&b));
      break;
    case 'f':
      any_set_fp(&sum, any_get_signed(&a) + any_get_signed(&b));
      break;
    default:
      assert(0);
  }
  return sum;
}

答案 2 :(得分:0)

你应该制作expr结构。这意味着AST的一个节点(Abstruct Syntax Tree)。它有操作。对于lhs,rhs,这意味着+, - ,*,/。 do_expr caluculate表达式。最后,dump_any打印该值。

#include <stdio.h>
#include <assert.h>

typedef enum any_type{
  ANY_TYPE_CHAR,
  ANY_TYPE_UCHAR,
  ANY_TYPE_SHORT,
  ANY_TYPE_USHORT,
  ANY_TYPE_INT,
  ANY_TYPE_UINT,
  ANY_TYPE_LONG,
  ANY_TYPE_ULONG,
  ANY_TYPE_FLOAT,
  ANY_TYPE_DOUBLE,
} any_type;

typedef struct any{
  any_type type;
  union{
    char as_char;
    unsigned char as_uchar;
    short as_short;
    unsigned short as_ushort;
    int as_int;
    unsigned int as_uint;
    long as_long;
    unsigned long as_ulong;
    float as_float;
    double as_double;
  };
} any;

typedef enum op_type{
  OP_PLUS,
  OP_MINUS,
  OP_MULT,
  OP_DIVID,
} op_type;

typedef struct {
  int op;
  any lhs;
  any rhs;
} expr;

int
do_expr(expr* e, any *r) {
  switch (e->op) {
    case OP_PLUS:
      r->type = e->lhs.type;
      r->as_int = e->lhs.as_int + e->rhs.as_int;
      return 0;
      break;
    default:
      fprintf(stderr, "unknown operation\n");
      break;
  }
  return 1;
}

void
dump_any(any* a) {
  switch (a->type) {
    case ANY_TYPE_INT:
      printf("%d\n", a->as_int);
      break;
    default:
      assert(!"unknown type");
      break;
  }
}

int
main(int argc, char* argv[]) {
  expr e1 = {
    .op = OP_PLUS,
    .lhs = { .type = ANY_TYPE_INT, as_int: 1, },
    .rhs = { .type = ANY_TYPE_INT, as_int: 2, },
  };

  any ret;
  if (do_expr(&e1, &ret) == 0) {
    dump_any(&ret);
  }

  return 0;
}

答案 3 :(得分:0)

很抱歉,您必须进行大小写切换,因为编译器必须为不同类型生成不同的CPU指令。操作的类型由变量的选择定义。