繁体   English   中英

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

[英]How do I have a variable in C that can accept various types?

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

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

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

谢谢。

定义可以包含多种类型值的变量的方法是使用联合:

union uu {
  int i;
  float f;
  char c;
  char *s;
} x;

xi是整数,xs是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);
 ....

真的很难看

还有其他可能性与宏处理器一起使用,使其更加令人愉悦,但实质上是您必须事先知道存储在并集中的值的类型并访问正确的字段。

这不是一件容易的事,但这是最简单的方法:

您需要知道所支持的所有类型,以及插入它们时的类型。

首先,你实际上有一些像struct { void * data; enum Type tag } struct { void * data; enum Type tag }

并定义enum Type { int, char*, ... etc }

void *是指向没有类型的数据的指针,因此您可以使用它来存储包含要存储的数据的内存块。

Type标记存储数据的内容,以便使用它的代码可以知道从数据结构返回的内容。

如果您不需要存储类型,并且可以在将其从数据结构中拉出时将其强制转换为正确的类型,那么您可以省略Type标记并仅存储void *

在C中,没有简单的方法可以做到这一点。 您可以使用void *并传递指向类型的指针,但不存在模板或泛型或变体的概念。

要使用void *,您需要将所有内容视为指针,因此必须在堆上分配它。 然后,当发送到此数据结构然后在另一侧回送时,您需要将这些指针强制转换为void *。 这可能很棘手,因为您必须记住类型的开头。

如果您碰巧在Windows上编程,可以使用Variants来执行此操作,但是会有一些与之相关的开销。

你可能想要void *

你有两个选择:

void* foo;

它可以指向任何类型的数据,或:

union my_types {
   int* i;
   char* s;
   double* d;
   bool* b;
   void* other;
}

它为您提供“自动”指针转换(您可以引用类型为“my_types”的变量,就像它是上述任何类型一样)。 有关工会的更多信息,请参阅此链接

这两个都不是一个很好的选择 - 考虑一下你正在尝试做什么的C ++。

使用void *

您可以根据需要进行类型转换,当然您必须自己进行检查。

您的解决方案必须使用指针来取消。 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);
    }
}

代码未经测试

您可以使用void *指针接受指向几乎所有内容的指针。 回到你想要的类型是一个棘手的部分:你必须在某处存储关于指针的类型信息。

您可以做的一件事是使用struct来存储void *指针和类型信息,并将其添加到您的数据结构中。 主要问题是类型信息本身; C不包含任何类型的反射,因此您可能必须创建类型的枚举或存储描述该类型的字符串。 然后,您必须通过查询类型信息强制struct的用户从void *强制转换回原始类型。

不是一个理想的情况。 一个更好的解决方案可能是转向C ++甚至C#或Java。


enum _myType { CHAR, INT, FLOAT, ... }myType;
struct MyNewType
{
   void * val;
   myType type;
}

然后,您可以将MyNewType类型的元素传递给您的函数。 检查类型并执行适当的铸造。

C提供了适合您目的的联合,您需要在编译之前定义所有类型,但同一个变量可以指向您在联合中包含的所有类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM