我正在寻找在C中实现字典数据结构,我想尽可能通用。也就是说它可以接受一对可以是任何类型的值。
如何初始化一个可以接受任何类型的变量?
如何将该类型转换回我想要的类型? (类型转换)
感谢。
答案 0 :(得分:8)
定义一个可以包含多种类型值的变量的方法是使用联合:
union uu {
int i;
float f;
char c;
char *s;
} x;
x.i是一个整数,x.s是一个char指针等,x的大小是成员类型大小中的最大值。
不幸的是,记住变量类型的唯一方法是将其存储在其他地方。一个常见的解决方案是拥有这样的结构:
struct ss {
int type;
union {
int i;
float f;
char c;
char *s;
} val;
} x;
做类似的事情:
#define FLOAT 1
#define INT 2
....
x.val.i = 12;
x.type = INT;
....
if (x.type = INT) printf("%d\n",x.val.i);
....
非常难看。
还有其他一些可能性与宏处理器一起使用,使它更加引人注目,但实质上是你必须事先知道 存储在联合中的值的类型并访问适当的领域。
答案 1 :(得分:7)
这不是一件容易的事,但这是最简单的方法:
您需要知道您支持的所有类型,以及插入它们时的内容。
首先,您实际上将拥有某些结构的数据结构
struct { void * data; enum Type tag }
并定义enum Type { int, char*, ... etc }
void *
是指向没有类型的数据的指针,因此您可以使用它来存储包含您要存储的数据的内存块。
Type标记存储数据的内容,以便使用它的代码可以知道从数据结构返回的内容。
如果您不需要存储该类型,并且可以在将其从数据结构中拉出时将其强制转换为正确的类型,那么您可以省略Type标记并只存储void *
< / p>
答案 2 :(得分:4)
在C中没有简单的方法可以做到这一点。您可以使用void *并传递指向类型的指针,但不存在模板或泛型或变体的概念。
要使用void *,您需要将所有内容视为指针,因此必须在堆上进行分配。然后,当发送到此数据结构然后在另一侧回送时,您需要将这些指针强制转换为void *。这可能很棘手,因为你必须记住类型的开头。
如果你碰巧在Windows上进行编程,可以使用Variants来执行此操作,但是会有一些与之相关的开销。
答案 3 :(得分:2)
您可能想要void *
。
答案 4 :(得分:2)
你有两个选择:
void* foo;
可以指向任何类型的数据,或者:
union my_types {
int* i;
char* s;
double* d;
bool* b;
void* other;
}
为您提供“自动”指针转换(因为您可以引用“my_types”类型的变量,就像它是上述任何类型一样)。有关工会的更多信息,请参阅this link。
两者都不是一个很好的选择 - 考虑使用C ++来实现你的目标。
答案 5 :(得分:1)
使用void *
?
您可以根据自己的需要进行类型转换,当然您必须自己进行检查。
答案 6 :(得分:1)
您的解决方案必须使用指针来取消。 void指针可以保存任何对象类型(不是函数)的地址,并且可以在不丢失信息的情况下转换回来。
最好是使用“父结构”,以便您知道对象指针的类型:
enum MyType { INTEGER, DOUBLE_STAR };
struct anytype {
enum MyType mytype;
size_t mysize;
void *myaddress;
};
然后
struct anytype any_1, any_2;
int num_chars;
double array[100];
any_1.mytype = INTEGER;
any_1.myaddress = &num_chars;
any_1.mysize = sizeof num_chars;
any_2.mytype = DOUBLE_STAR;
any_2.myaddress = array;
any_2.size = sizeof array;
,并与之合作
foo(any_1);
foo(any_2);
其中foo
定义为
void foo(struct anytype thing) {
if (thing.mytype == INTEGER) {
int *x = thing.myaddress;
printf("the integer is %d\n", *x);
}
if (thing.mytype == DOUBLE_STAR) {
size_t k;
double *x = thing.myaddress;
double sum = 0;
for (k = 0; k < thing.mysize; k++) {
sum += thing.myaddress[k];
}
printf("sum of array: %f\n", sum);
}
}
未经测试的代码
答案 7 :(得分:0)
您可以使用void *
指针接受指向几乎所有内容的指针。回到你想要的类型是一个棘手的部分:你必须在某处存储关于指针的类型信息。
您可以做的一件事是使用struct
来存储void *
指针和类型信息,并将其添加到您的数据结构中。主要问题是类型信息本身; C不包含任何类型的反射,因此您可能必须创建类型的枚举或存储描述该类型的字符串。然后,您必须通过查询类型信息强制struct
的用户从void *
强制转换回原始类型。
不理想的情况。一个更好的解决方案可能是转向C ++甚至C#或Java。
答案 8 :(得分:0)
enum _myType { CHAR, INT, FLOAT, ... }myType;
struct MyNewType
{
void * val;
myType type;
}
然后你可以将MyNewType类型的元素传递给你的函数。检查类型并执行适当的铸造。
答案 9 :(得分:0)
C提供可能适合您的目的的联合,您需要在编译之前定义所有类型,但同一个变量可以指向您在联合中包含的所有类型。