将运算符作为参数传递给C99

时间:2016-03-17 00:43:12

标签: c operators parameter-passing c99

我想在C99中将运算符作为参数传递。 我的解决方案是:

int add(int l, int r)
{
    return l + r;
}

int sub(int l, int r)
{
    return l - r;
}

// ... long list of operator functions

int perform(int (*f)(int, int), int left, int right)
{
    return f(left, right);
}

int main(void)
{
    int a = perform(&add, 3, 2);
}

还有其他方法吗?我不想为每个操作员编写一个函数。

看起来像这样:

int a = perform( something_cool_here , 3, 2);

2 个答案:

答案 0 :(得分:4)

您可以使用开关/案例,例如:

int perform(char op,int a,int b)
{
    switch (op)
    {
    case '+': return a+b;
    case '-': return a-b;
    default: return 0;
    }
}

但是你仍然需要为每个运算符编写一些代码;你不能在C中免费获得任何东西。

答案 1 :(得分:3)

您可以使用X Macros。通过在可重定义宏中定义包含重复值表的单个宏,您可以重新定义当前任务的内部宏,并插入一个宏来处理整个集。

这是一个以单操作数浮点内置为例的紧凑方法。其他类型的过程类似。

//add name of each function you want to use here:
#define UNARYFPBUILTINS \
    $(acos)  $(acosh)  $(asin)  $(asinh)  $(atan)   $(atanh)  $(cbrt)  $(ceil)  \
    $(cos)   $(erf)    $(erfc)  $(exp)    $(exp10)  $(exp2)   $(expm1) $(fabs)  \
    $(floor) $(gamma)  $(j0)    $(j1)     $(lgamma) $(log)    $(log10) $(log1p) \
    $(log2)  $(logb)   $(pow10) $(round)  $(signbit)          $(significand)  \
    $(sin)   $(sqrt)   $(tan)   $(tgamma) $(trunc)  $(y0)     $(y1)

//now define the $(x) macro for our current use case - defining enums
#define $(x) UFPOP_##x,
enum ufp_enum{ UNARYFPBUILTINS };
#undef $  //undefine the $(x) macro so we can reuse it

//feel free to remove the __builtin_## ... its just an optimization
double op(enum ufp_enum op, double f){
  switch(op){  //now we can use the same macros for our cases
#define $(x) case UFPOP_##x : f = __builtin_##x(f);break;
   UNARYFPBUILTINS
#undef $
  }
  return f;
}

您可以继续将其用于其他内容

///////////EXTRA STUFF/////////
//unused - may be good mapping the enums to strings
//#define $(x) #x,
//const char * ufp_strings{ UNARYFPBUILTINS };
//#undef $

//this uses float instead of double, so adds the ##f to each function
float opf(enum ufp_enum op, float f){
  switch(op){
#define $(x) case UFPOP_##x : f = __builtin_##x##f(f);break;
    UNARYFPBUILTINS
#undef $
  }
  return f;
}

//you could do the same thing for long double here

编辑:请注意,宏中的$是依赖于实现的,你可以调用它

Edit2:这是一个有多个参数来做算术运算符的例子。这个使用计算得到的而不是开关,以防你的编译器比另一个更好地处理一个。

#define IOPS $(SUB,-) $(MUL,*) $(DIV,/) $(MOD,%) $(ADD,+) $(AND,&) $(OR,|) \
  $(XOR,^) $(SR,>>) $(SL,<<)

enum iops_enum {
#define $(x,op)   IOPSENUM_##x,
  IOPS
  IOPSENUM_COUNT
#undef $
};
int opi(int a, enum iops_enum b, int c){
  static const char array[] = { //you may get better results with short or int
#define $(x,op)   &&x - &&ADD,
    IOPS
#undef $
  };
  if (b >= IOPSENUM_COUNT) return a;
  goto *(&&ADD + array[b]);
  //else should give a warning here.
#define $(x,op)   x: return a op c;
  IOPS
#undef $
}