2

我有两个链表:-

struct Struct_A_s {
int a;
struct  Struct_A_s *next;
}Struct_A;

struct Struct_B_s {
int a;
int b;
int c;
int d;
struct  Struct_B_s *next;
}Struct_B;

我已经有几个在 Struct_A 上运行的函数。像 :

“Add_tail (Struct_A *)”、“Remove_tail(Struct_B *)”、“Add_node(Struct_A *,int pos)”、Add_head 等都已到位。

对我的要求是我应该修改现有的函数,以便它们可以在 Struct_A 和 Struct_B 上运行。

在 C 中,有没有办法传递 void 指针(或类似的东西)并编写一些通用代码来处理 Struct_A 和 Struct_B。代码大小在这里是一个大问题。目前我看到的唯一选择是从头开始为 Struct_B 重写所有代码(链表操作)。

4

3 回答 3

2

有几种方法可以解决。我敢肯定,其他人比我可能有其他人建议的更熟练。

  • 选项 A:传递一个 void 指针和某种数据类型的指示,然后对其进行转换。
  • 选项 B:将两个指针组合成一个并集并传递它。
  • 选项 C:将类型和联合组合成一个结构并传递它
  • 选项 D:使用更受尊重的替代方案来代替工会

一些示例代码...

enum DataType { TYPE_1, TYPE_2 };

struct Type1 { ... };
struct Type2 { ... };

union Data
{
    void*         addr;
    struct Type1* type1;
    struct Type2* type2;
}

struct Object
{
    DataType type;
    union Data data;
}

struct Thing
{
    DataType type;
    void* data;
}

void someFunc1( void* data, DataType type )
{
   switch( type )
   {
       case TYPE_1:
       {
           struct Type1* type1 = (struct Type1*)data;
           ...
           break;
       }
       case TYPE_2:
       {
           struct Type2* type2 = (struct Type2*)data;
           ...
           break;
       }
   }
}

void someFunc2( union Data* data, DataType type )
{
   switch( type )
   {
       case TYPE_1:
       {
           struct Type1* type1 = data->type1;
           ...
           break;
       }
       case TYPE_2:
       {
           struct Type2* type2 = data->type2;
           ...
           break;
       }
   }
}

void someFunc3( struct Object* object )
{
   switch( object->type )
   {
       case TYPE_1:
       {
           struct Type1* type1 = object->data.type1;
           ...
           break;
       }
       case TYPE_2:
       {
           struct Type2* type2 = object->data.type2;
           ...
           break;
       }
   }
}


void someFunc4( struct Thing* thing )
{
   switch( thing->type )
   {
       case TYPE_1:
       {
           struct Type1* type1 = (struct Type1*)thing->data;
           ...
           break;
       }
       case TYPE_2:
       {
           struct Type2* type2 = (struct Type2*)thing->data;
           ...
           break;
       }
   }
}

以另一种方式看待这个......如果你有一个只需要的方法,a那么你可以做这样的事情......

void myFunc( int a ) { ... };

void someFunc3( struct Object* object )
{
    myFunc( object->type == TYPE_1 ? object->data.type1->a : object->data.type2->a );
}

更好的是...修改函数以接受对象并仅在底部区分...

void myFunc( struct Object* object )
{
   int* a;

   switch( object->type )
   {
       case TYPE_1:
       {
           a = &object->data.type1->a
           break;
       }
       case TYPE_2:
       {
           a = &object->data.type2->a;
           break;
       }
       default:
       {
           abort();
       }
   }

   // do work with a as though it were passed in as a pointer to int

   if( object->type == TYPE_2 )
   {
      // do additional work with the b, c, d elements, etc.
   }
}
于 2013-05-07T19:11:52.067 回答
1

是的,您可以void *在本来会使用Struct_A *or的地方使用Struct_B *. 您需要仔细设计您的 API。通常,您最终会有点像bsearch()qsort()采用一个或多个函数指针来执行特定于结构的操作(在 and 的情况下进行比较bsearch()qsort()

请注意,遍历您的链表会很困难,因为下一个指针位于结构中的不同偏移量处。void *使用包含下一个指针和指向实际结构的固定通用列表结构可能会做得更好。

typedef struct List List;

struct List
{
    List *next;
  //List *prev;   // Doubly-linked lists
    void *data;
};

这是“侵入式”和“非侵入式”列表结构之间的区别。您现有的设计使用侵入式列表结构;修改列表中的结构以包含指针。建议的替代设计是非侵入式的;您可以创建任何结构类型的列表,而无需修改结构类型。

于 2013-05-07T19:11:45.617 回答
0

您可以重新定义结构,如下所示。您必须根据类型进行大量转换才能修改所有早期功能以同时适用于两者。您需要同时使用 Struct_A * 。

struct Struct_A_s {
    int type;
    Struct_A_s *next;
    int a;
}Struct_A;

struct Struct_B_s {
    int type;
    Struct_A *next;
    int a;
    int b;
    int c;
    int d;
}Struct_B;
于 2013-05-07T19:16:54.397 回答