我有一个结构
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位。 问题-如何在运行时将其转换为适当的类型(而不是(??? *))?
答案 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 ....
}