简体   繁体   English

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

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

I'm looking to implement a dictionary data structure in C which I want to be as generic as possible. 我想在C中实现一个字典数据结构,我想尽可能通用。 That is to say it can accept a pair of values that can be of any type. 也就是说它可以接受一对可以是任何类型的值。

How can I init a variable that can accept any types? 如何初始化一个可以接受任何类型的变量?

And how can I convert that type back to a type I want? 如何将该类型转换回我想要的类型? (Typecast) (类型转换)

Thanks. 谢谢。

The way to define a variable that can hold values of more than one type is to use unions: 定义可以包含多种类型值的变量的方法是使用联合:

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

xi is an integer, xs a char pointer etc. and the size of x is the maximum among the sizes of the members type. xi是整数,xs是char指针等,x的大小是成员类型的大小中的最大值。

Unfortunately the only way to remember the type of the variable is to store it somewhere else. 不幸的是,记住变量类型的唯一方法是将其存储在其他地方。 A common solution is to have a structure like this: 一个常见的解决方案是拥有这样的结构:

 struct ss {
   int type;
    union {
      int i;
      float f;
      char c;
      char *s;
    } val;
  } x;

And do something like: 做一些像:

 #define FLOAT 1
 #define INT   2
 .... 

 x.val.i = 12;
 x.type = INT;
 ....
 if (x.type = INT) printf("%d\n",x.val.i);
 ....

really ugly. 真的很难看

There are other possibility playing with the macro processor to make it a little bit more pleasent to the eye but the essence is that you have to know in advance the type of the value stored in the union and access the proper field. 还有其他可能性与宏处理器一起使用,使其更加令人愉悦,但实质上是您必须事先知道存储在并集中的值的类型并访问正确的字段。

This isn't trivial to do, but here's the simplest way to do it: 这不是一件容易的事,但这是最简单的方法:

You need to know all the types you'll support, and what they are when you insert them. 您需要知道所支持的所有类型,以及插入它们时的类型。

First, you'll actually have a data structure of some struct like struct { void * data; enum Type tag } 首先,你实际上有一些像struct { void * data; enum Type tag } struct { void * data; enum Type tag }

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

The void * is a pointer to data without a type, so you can use it to store to a chunk of memory that contains the data you want to store. void *是指向没有类型的数据的指针,因此您可以使用它来存储包含要存储的数据的内存块。

The Type tag stores what the data is so that your code using it can know what is being returned from your data structure. Type标记存储数据的内容,以便使用它的代码可以知道从数据结构返回的内容。

If you don't need to store the type, and you can cast it back to the correct type when you pull it out of your data structure, then you can omit the Type tag and just store void * 如果您不需要存储类型,并且可以在将其从数据结构中拉出时将其强制转换为正确的类型,那么您可以省略Type标记并仅存储void *

In C there is no easy way to do this. 在C中,没有简单的方法可以做到这一点。 You can use void* and pass around pointers to the types, but there is no concept of templates or generics or variants that exists. 您可以使用void *并传递指向类型的指针,但不存在模板或泛型或变体的概念。

To use void* you would need to treat everything as a pointer so would have to allocate it on the heap. 要使用void *,您需要将所有内容视为指针,因此必须在堆上分配它。 You would then need to cast those pointers to void* when sending to this data structure and then cast back on the other side. 然后,当发送到此数据结构然后在另一侧回送时,您需要将这些指针强制转换为void *。 This can be tricky because you have to remember what the types were to start with. 这可能很棘手,因为您必须记住类型的开头。

If you happen to be programming on Windows you can use Variants to do this, but there is some overhead associated with it. 如果您碰巧在Windows上编程,可以使用Variants来执行此操作,但是会有一些与之相关的开销。

你可能想要void *

You've got two options: 你有两个选择:

void* foo;

which can point to data of any type, or: 它可以指向任何类型的数据,或:

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

which gives you "automatic" pointer casting (in that you can reference a variable of type "my_types" as if it were any of the above types). 它为您提供“自动”指针转换(您可以引用类型为“my_types”的变量,就像它是上述任何类型一样)。 See this link for more on unions. 有关工会的更多信息,请参阅此链接

Neither is a great option -- consider C++ for what you're trying to do. 这两个都不是一个很好的选择 - 考虑一下你正在尝试做什么的C ++。

Use a void * ? 使用void *

You can typecast to whatever you want provided of course you must perform the checking yourself. 您可以根据需要进行类型转换,当然您必须自己进行检查。

Your solution will have to use pointers to void. 您的解决方案必须使用指针来取消。 Pointers to void can hold the address of any object type (not functions) and can be converted back without loss of information. void指针可以保存任何对象类型(不是函数)的地址,并且可以在不丢失信息的情况下转换回来。

Best is to use a "parent structure" so that you know the type of the object pointer to: 最好是使用“父结构”,以便您知道对象指针的类型:

enum MyType { INTEGER, DOUBLE_STAR };
struct anytype {
    enum MyType mytype;
    size_t mysize;
    void *myaddress;
};

and then 接着

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;

and, to work with that 并且,与之合作

foo(any_1);
foo(any_2);

where foo is defined as 其中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);
    }
}

CODE NOT TESTED 代码未经测试

You can use a void * pointer to accept a pointer to pretty much anything. 您可以使用void *指针接受指向几乎所有内容的指针。 Casting back to the type you want is the tricky part: you have to store the type information about the pointer somewhere. 回到你想要的类型是一个棘手的部分:你必须在某处存储关于指针的类型信息。

One thing you could do is use a struct to store both the void * pointer and the type information, and add that to your data structure. 您可以做的一件事是使用struct来存储void *指针和类型信息,并将其添加到您的数据结构中。 The major problem there is the type information itself; 主要问题是类型信息本身; C doesn't include any sort of type reflection, so you'll probably have to create an enumeration of types or store a string describing the type. C不包含任何类型的反射,因此您可能必须创建类型的枚举或存储描述该类型的字符串。 You would then have to force the user of the struct to cast back from the void * to the original type by querying the type information. 然后,您必须通过查询类型信息强制struct的用户从void *强制转换回原始类型。

Not an ideal situation. 不是一个理想的情况。 A much better solution would probably be to just move to C++ or even C# or Java. 一个更好的解决方案可能是转向C ++甚至C#或Java。


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

Then you could pass elements of type MyNewType to your functions. 然后,您可以将MyNewType类型的元素传递给您的函数。 Check the type and perform the proper casting. 检查类型并执行适当的铸造。

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

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

相关问题 如何在c中获取各种类型的大小? - How can I get the sizes of various types in c? 如何在C语言中读取各种类型的用户输入? - How to read user input of various types in C? zlib添加的各种类型的目的是什么?如何使用它们? - What is the purpose of the various types added by zlib and how can I use them? 如何在Python C / C ++扩展之间共享一个全局C / C ++变量? - How can I have a global C/C++ variable that is shared between Python C/C++ extensions? 如何使函数返回C中多个变量类型的结果? - How do I make a function return the result of multiple variable types in C? 如何检查C中的变量是否属于某种类型(比较两种类型)? - How do I check if a variable is of a certain type (compare two types) in C? 不支持重载函数时,C语言中的math.h函数如何接受多种类型的参数? - How do math.h functions in C accept arguments of multiple types when overloading functions are not supported? 如何只接受C语言文件中的数值? - How do I accept only the numeric values from a file in C? 宏可以接受类型吗? - Can macros accept types? 我有接受地址的函数,但我想打印变量的值..我该怎么办? - i have function which accepts the address,but i want to print value of the variable.. how can i do?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM