我有两个链接列表: -
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重写所有代码(链表操作)。
答案 0 :(得分:2)
有几种方法可以解决它。我相信其他人比我可能有其他人更有技巧。
一些示例代码......
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.
}
}
答案 1 :(得分:1)
是的,您可以使用void *
,否则请使用Struct_A *
或Struct_B *
。您需要仔细设计API。通常,您最终会像bsearch()
和qsort()
那样使用一个或多个执行结构特定操作的函数指针(在bsearch()
和{{1的情况下进行比较) }})。
请注意,遍历链接列表会很困难,因为下一个指针位于结构中的不同偏移处。使用包含下一个指针和实际结构qsort()
的固定通用列表结构,您可能会做得更好。
void *
这是'侵入'和'非侵入'列表结构之间的区别。您现有的设计使用侵入式列表结构;修改列表中的结构以包括指针。替代建议的设计是非侵入性的;您可以在不修改结构类型的情况下创建任何结构类型的列表。
答案 2 :(得分: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;