在C函数中传递通用参数

时间:2019-05-12 10:48:13

标签: c

我有一个结构

typedef struct
{  
    void *l_var;      
    void *r_var;    
}EXPR;

EXPR expr;

我将其初始化

expr.l_var = &motor_rt_params[0].position;
expr.r_var = &motor_rt_params[1].position;

现在我要使用这些值

void SCRIPT_Process(void *l_var, void *r_var, uint32_t oper)
{
    int32_t res;

    switch (oper)
    {
        case OP_PLUS: 
          res = *((??? *) l_var) + *((??? *)r_var);
          break;
        case OP_MINUS: 
          res = *((??? *) l_var) - *((??? *)r_var);
          break; 
    }
}

SCRIPT_Process(expr.l_var , expr.r_var , OP_PLUS);

变量可以是32、16、8位。 问题-如何在运行时将其转换为适当的类型(而不是(??? *))?

4 个答案:

答案 0 :(得分:2)

初始化指针时还要节省大小吗?

typedef struct
{  
    void *l_var;      
    void *r_var;    
    size_t sz;
}EXPR;

expr.l_var = &motor_rt_params[0].position;
expr.r_var = &motor_rt_params[1].position;
expr.sz = sizeof(motor_rt_params[1].position);

例如允许

void SCRIPT_Process(void *l_var, void *r_var, size_t sz, uint32_t oper)
{
    int32_t res;

    switch (oper)
    {
        case OP_PLUS: 
          if (sz == sizeof(int32_t))
            res = *((int32_t *) l_var) + *((int32_t *)r_var);
          else /* suppose a int16_t */
            res = *((int16_t *) l_var) + *((int16_t *)r_var);
          break;
        case OP_MINUS: 
          if (sz == sizeof(int))
            res = *((int32_t *) l_var) - *((int32_t *)r_var);
          else /* suppose a int16_t */
            res = *((int16_t *) l_var) - *((int16_t *)r_var);
    }
}

SCRIPT_Process(expr.l_var , expr.r_var , expr.sz, OP_PLUS);

仅假设为 int short ,我让您添加int8_t

的大小写

将大小放到EXPR中的优点是不会丢失该信息/不会由于在不同代码段中进行管理而错误地导致不一致。

或者可以将SCRIPT_Process的参数中的EXPR而不是字段分开?

也许您还需要知道是带符号的还是无符号的,带有一个附加字段或使用一个 int 的大小来计算无符号(4、2或1)的正数和负数的正数以获得带符号的(-4,-2 -1)。

另一种方法是保存指向正确函数的指针,而不是保存大小,这是一种C ++虚拟实现。

当然,所有这一切都假定您无法在结构中将值另存为int32_t,而您确实需要保存指针。

答案 1 :(得分:1)

安全且相同。没有指针调整。联合中的类型列表可能会更长

typedef union
{
    int8_t u8;
    int16_t u16;
    int32_t u32;
}data_t;


int32_t get(data_t *o, int size)
{
    switch (size)
    {
        case 8: 
           return o -> u8;
          break;
        case 16: 
           return o -> u16;
          break; 
        default: 
          return o -> u32;
          break; 
    }
}

void SCRIPT_Process(data_t *l_var, data_t *r_var, uint32_t oper, int sizel, int sizer)
{
    int32_t res;
    int32_t l = get(l_var, sizel);
    int32_t r = get(r_var, sizer);


    switch (oper)
    {
        case OP_PLUS: 
          res = l + r;
          break;
        case OP_MINUS: 
          res = l -r;
          break; 
          /* ..... */
    }
}

答案 2 :(得分:0)

您可以简单地将值存储在void*中,而不是它们的地址中:

expr.l_var = (void*)motor_rt_params[0].position;
expr.r_var = (void*)motor_rt_params[1].position;

然后使用它们,将其强制转换为intptr_t(值,而不是指针)。确保这些类型与指针的宽度相同,因此您不再需要关心源值的宽度。

答案 3 :(得分:0)

  

变量可以是32、16、8位。

所以您需要知道:

  • 变量地址
  • 变量类型和
  • 操作

您需要传递这些信息。

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

enum type_e {
    TYPE_u8,
    TYPE_u16,
    TYPE_u32,
    // TODO: add more, ex. TYPE_INT, TYPE_DOUBLE, etc.
};

enum oper_e {
    OP_PLUS,
    OP_MINUS,
    // TODO: add mode, ex. OP_POW or OP_DIV etc. 
};

void SCRIPT_Process(void *res, const void *l, const void *r, enum type_e type, enum oper_e oper)
{
    switch (oper) {
    case OP_PLUS:
        switch (type) {
        case TYPE_u8:
            *(uint8_t*)res = *(uint8_t*)l + *(uint8_t*)r;
            break;
        case TYPE_u16:
            *(uint16_t*)res = *(uint16_t*)l + *(uint16_t*)r;
            break;
        case TYPE_u32:
            *(uint32_t*)res = *(uint32_t*)l + *(uint32_t*)r;
            break;
        default:
            assert(0);
        }
        break;
     case OP_MINUS:
        // TODO:
        assert(0);
    }
}

int main() {
    uint32_t l = 5, r = 2, res;
    SCRIPT_Process(&res, &r, &l, TYPE_u32, OP_PLUS);
    printf("%d + %d = %d\n", (int)l, (int)r, (int)res);
}

最好提供一个宏,以使代码更冗长且键入更少:

#define SCRIPT_PROCESS_MACRO(type, res, l, op, r) \
      *(type*)res = *(type*)l op *(type*)r;

void SCRIPT_Process(void *res, void *l, void *r, enum type_e type, enum oper_e oper)
{
    switch (oper) {
    case OP_PLUS:
        switch (type) {
        case TYPE_u8:
            SCRIPT_PROCESS_MACRO(uint8_t, res, l, +, r);
            break;
        case TYPE_u16:
            SCRIPT_PROCESS_MACRO(uint16_t, res, l, +, r);
            break;
        case TYPE_u32:
            SCRIPT_PROCESS_MACRO(uint32_t, res, l, +, r);
            break;
        default:
            assert(0);
        }
        break;
     case OP_MINUS:
        // TODO:
        assert(0);
    }
}

或更简单的使用更多的宏,这使得添加新的操作和类型变得微不足道:

#define SCRIPT_PROCESS_MACRO(type, res, l, op, r) \
      *(type*)res = *(type*)l op *(type*)r;

#define SCRIPT_PROCESS_TYPE_CASES(type, res, l, op, r) \
    switch (type) { \
    case TYPE_u8: SCRIPT_PROCESS_MACRO(uint8_t, res, l, op, r); break; \
    case TYPE_u16: SCRIPT_PROCESS_MACRO(uint16_t, res, l, op, r); break; \
    case TYPE_u32: SCRIPT_PROCESS_MACRO(uint32_t, res, l, op, r); break; \
    default: assert(0); break; \
    }

void SCRIPT_Process(void *res, void *l, void *r, enum type_e type, enum oper_e oper)
{
    switch (oper) {
    case OP_PLUS:
        SCRIPT_PROCESS_TYPE_CASES(type, res, l, +, r);
        break;
     case OP_MINUS:
        SCRIPT_PROCESS_TYPE_CASES(type, res, l, -, r);
        break;
    }
}

或者您甚至可以使用更通用的解决方案,对结果,左和右操作数具有不同的类型:

   void SCRIPT_Process(
         void *res, enum type_e restype,
         const void *l, enum type_e ltype,
         const void *r, enum type_e rtype,
         enum oper_e oper) {
     if (restype == TYPE_u8 && ltype == TYPE_u32 && rtype == TYPE_u16 && oper == OP_ADD) {
           *(uint8_t*)res = *(uint32_t*)ltype + *(uint16_t*)rtype;
     } if ( // and so on so on so on so on ....
  }