2

基于对将变量类型作为函数参数传递的问题的答案:

我可以写这样的东西:

enum {
    TYPEA,
    TYPEB,
    TYPEC,
    TYPED
} TYPE;

void foo(TYPE t, void* x){
    switch(t){
        case TYPEA:
            struct A* y = (struct A*)x;
                            //do something with a member named "next"   
            break;
        case TYPEB:
            struct B* y = (struct B*)x;
                            //do something with a member named "next" 
         ...
    }
}

有什么办法可以避免多次重写“有一个名为 next 的成员的东西”?

我们假设 A 和 B 中的“下一个”在每个结构中的相对内存位置不同。

4

4 回答 4

2

假设枚举的项目没有给定自定义数字,您可以通过使用函数指针来执行 switch 语句的紧凑版本。

enum {
    TYPEA,
    TYPEB,
    TYPEC,
    TYPED,

    TYPE_N // number of enum items
} TYPE;


typedef void(*type_func_t)(void*);



static void TYPEA_specific (void* x) 
{
  struct A* y = x;

  // specific stuff related to TYPEA here

  do_something_with_next(y->next);
}

static void TYPEB_specific (void* x) 
{
  struct B* y = x;

  // specific stuff related to TYPEB here

  do_something_with_next(y->next);
}



static const type_func_t TYPE_HANDLER [TYPE_N] = 
{
  TYPEA_specific,
  TYPEB_specific
  ...
};


inline void foo (TYPE t, void* x)
{
  TYPE_HANDLER[t](x);
}
于 2012-12-07T12:53:11.417 回答
1

此解决方案使用宏:

#include <stdio.h>

#define POLYCAST_AB(etype, target, member) \
  *((etype) == TYPEA ? &((struct A *)(target))->member :  \
    (etype) == TYPEB ? &((struct B *)(target))->member : 0)

enum TYPE {
   TYPEA,
   TYPEB
};

struct A {
   int next;
} a = {42};

struct B {
   int i;
   int next;
} b = {43, 44};

static void foo(enum TYPE t, void *x) {
   POLYCAST_AB(t, x, next) += 100;  // <-- most other answers can't do this
   printf("next=%d\n", POLYCAST_AB(t, x, next));
}

int main(void) {
   foo(TYPEA, &a);   
   foo(TYPEB, &b);   
   return 0;
}

如果你不需要左值,你可以在宏定义中省略额外的*和(也省略所有都具有相同类型&的假设)。next

于 2012-12-07T15:09:13.140 回答
0

当然,C 没有结构成员的动态查找。

节省最多击键的解决方案可能是使用宏。

此外,从void *.

于 2012-12-07T10:03:10.983 回答
0

在每个case中,您可以获取 with 的地址,next然后&y.next将其传递给函数或将控制权转移到使用指针执行某些操作的代码next。这假定next在 each 中具有相同的类型struct,尽管它可能位于不同的位置。

以下是三个例子:

// Example 0:  Functional call.
switch(t)
{
    case TYPEA:
        MyFunction(&(struct A *)x->next);
        break;
    case TYPEB:
        MyFunction(&(struct B *)x->next);
        break;
}

// Example 1: Code after the switch.
TypeOfNext *next;
switch(t)
{
    case TYPEA:
        next = &(struct A *)x->next;
        break;
    case TYPEB:
        next = &(struct B *)x->next;
        break;
}
… code that uses next…

// Example 2: Code in the switch, with goto.
switch(t)
{
    TypeOfNext *next;
    case TYPEA:
        next = &(struct A *)x->next;
        goto common;
    case TYPEB:
        next = &(struct B *)x->next;
    common:
        … code that uses next…
        break;
}
于 2012-12-07T12:40:58.313 回答