代码之家  ›  专栏  ›  技术社区  ›  kirbo

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

  •  3
  • kirbo  · 技术社区  · 15 年前

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

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

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

    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次。 我怎样才能从空指针简化数据类型检查和强制转换?

    我能把这个代码做得更好吗?

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

    谢谢

    很酷,非常感谢这些回复,我明白你所说的函数指针是什么意思。 我会考虑并使用其中一种方法。谢谢

    4 回复  |  直到 15 年前
        1
  •  4
  •   dmckee --- ex-moderator kitten    15 年前

    简短回答: C根本不提供语法帮助。

    好消息: 您可以使用函数指针来支持C中的多态性。 有许多问题解释如何做 那个 堆栈溢出时已存在。一分钟后我会在一两个链接中编辑…

    不喜欢我找到的答案,所以这里。

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

    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] = { /* ... */
    

    现在,一般的add函数决定了它的两种类型 并通过索引到表中调用正确的函数。

        2
  •  3
  •   sth    15 年前

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

    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++这样支持面向对象和类似概念的语言可以使你的生活变得简单多了。

        3
  •  1
  •   dirkgently    15 年前
    • 你可以使用 switch 而不是多个 if-else .

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

    例如:

    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)
    
    ...
    
        4
  •  0
  •   Frederic    15 年前

    使用函数指针和switch语句可以很容易地做到这一点。