如何在C中有一个可以接受各种类型的变量?

时间:2009-11-18 20:37:26

标签: c

我正在寻找在C中实现字典数据结构,我想尽可能通用。也就是说它可以接受一对可以是任何类型的值。

如何初始化一个可以接受任何类型的变量?

如何将该类型转换回我想要的类型? (类型转换)

感谢。

10 个答案:

答案 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提供可能适合您的目的的联合,您需要在编译之前定义所有类型,但同一个变量可以指向您在联合中包含的所有类型。