使用void *指向数值数据的算术运算

时间:2010-02-23 22:35:54

标签: c parsing casting

我正在研究C中的小解析器和“方程求解器”,这个过程的一部分是对令牌进行算术运算。 每个标记包含指向数字数据的void *指针,以及定义数据类型的枚举。

这是该函数的示例,它通过添加另外两个令牌来创建新令牌。为了做到这一点,我需要

  1. 检查类型
  2. 铸造
  3. 做手术
  4. 从结果
  5. 创建新令牌

    Token* _CreateTokenByAddition(Token* arg1, Token* arg2){
        Token *tokenResult;
        if ((arg1->_type == tk_IntData) && (arg2->_type == tk_IntData)){
    
            int* intResult = malloc(sizeof(int));
            *intResult = *(int*)arg1->_data + *(int*)arg2->_data;
    
            tokenResult = CreateTokenFromValue(intResult, tk_IntData);
        }else
        if ((arg1->_type == tk_IntData) && (arg2->_type == tk_FloatData)){
    
            float* intResult = malloc(sizeof(float));
            *intResult = *(int*)arg1->_data + *(float*)arg2->_data;
            tokenResult = CreateTokenFromValue(intResult, tk_FloatData);
        }else
        if ((arg1->_type == tk_FloatData) && (arg2->_type == tk_IntData)){
    
            float* intResult = malloc(sizeof(float));
            *intResult = *(float*)arg1->_data + *(int*)arg2->_data;
            tokenResult = CreateTokenFromValue(intResult, tk_FloatData);
        }
        else
        if ((arg1->_type == tk_FloatData) && (arg2->_type == tk_FloatData)){
    
            float* intResult = malloc(sizeof(float));
            *intResult = *(float*)arg1->_data + *(float*)arg2->_data;
            tokenResult = CreateTokenFromValue(intResult, tk_FloatData);
        }
        return tokenResult;
    }
    

    我有几乎相同的函数 - ,*,/。我可能需要创造更多。

    问题是: 我如何创建一个支持所有简单操作的通用函数,如+ - * /? 我不想把这个函数放在宏中,然后通过替换数学操作数复制它4次。 我怎样才能简化数据类型检查和从void指针转换?

    我能以任何方式制作此代码,更好吗?

    假设:我没有任何非数字数据类型(例如字符串)

    由于

    很酷,非常感谢这些回复,我明白了你的功能指针是什么意思。 我将考虑它并使用这些方法之一。感谢

4 个答案:

答案 0 :(得分:4)

简答: c根本没有提供任何语法帮助。

好消息:您可以使用函数指针支持c中的多态性。 有许多问题解释了如何已经出现在Stack Overflow上。在一分钟内,我将在一两个链接中进行编辑......

不喜欢我为此用途找到的答案,所以这里就是。

对于每个操作,编写一组采用所有合法类型组合的函数。每个人都只做一个组合,所以很容易。然后构造一个像这样的函数指针表

typedef Token* (*mathfuncptr)(void *, void *);

Token* _Add_IntInt(void *, void *);
Token* _Add_IntFloat(void *, void *);
Token* _Add_FloatInt(void *, void *);
/* ... */

mathfuncptr Add_table[AddTypeCount][AddTypeCount] = {
  {_Add_IntInt,   _Add_IntFloat},
  {_Add_FloatInt, _Add_FloatFloat}
};
mathfuncptr Mul_table[MultTypeCount][MultTypeCount] = { /* ... */

现在你的常规添加功能决定了它拥有的两种类型并通过索引到表中来调用正确的函数。

答案 1 :(得分:3)

您可以将数学运算放在函数指针中,然后使用使用这些函数指针的泛型函数:

typedef int (*bin_op)(int, int);
typedef float (*bin_fop)(float, float);

Token* _CreateTokenByOp(Token* arg1, Token* arg2, bin_op op, bin_fop, fop) {
   ...
   *intResult = op(*(int*)arg1->_data, *(int*)arg2->_data);
   ...
}

int add(int a, int b) {  return a+b;  }
float addf(float a, float b) {  return a+b;  }
...

Token* _CreateTokenByAddition(Token* arg1, Token* arg2) {
   return _CreateTokenByOp(arg1, arg2, &add, &addf);
}

话虽这么说,C通常不擅长创建泛型函数,并且使用函数指针可以快速导致相当模糊的代码。使用像C ++这样支持面向对象和类似概念的语言可以让你的生活变得更轻松。

答案 2 :(得分:1)

  • 您可以使用switch代替多个if-else

  • 由与类型对应的枚举索引的函数指针表。

e.g:

typedef enum type_info_ { INT = 0, FLOAT, ... , UNKNOWN } TI;

   typdef void *(*generic_add_t)(void const*, void const*);

   void *float_add(void const* l, void const* r) {
        float *result = malloc(sizeof *result);
        *result = *((float const *)l) + *((float const *)r);
        return result;
   }




generic_add_t fp_table[] = { float_add, ... };

并将其用作:

  TI curr_type = UNKNOWN;
  // ...
  fp[ curr_type ];

如果你懒得推出所有加法器,请定义一个宏:

#define MAKE_ADDER(type) \
void *type##_add(void const* l, void const* r) { \
        type *result = malloc(sizeof *result); \
        *result = *((type const *)l) + *((type const *)r); \
        return result; \
   } 

并将其用作:

MAKE_ADDER(float)
MAKE_ADDER(int)

...

答案 3 :(得分:0)

您可以使用函数指针和switch语句轻松完成此操作。