如何检查C中的结构类型

时间:2015-07-23 19:23:18

标签: c

我在C中创建了一个简单的列表结构,它使用void *指针保存任何类型的数据,如:

struct node
{
    void *the_data;
    node *next;
};

它工作正常,但我有一些列表,例如,只包含列表中的struct_a和另一个列表中的struct_b。我需要在单个if()问题中检查列表的第一个元素是struct_a类型还是struct_b类型,因此我知道此列表所持有的数据。这该怎么做?感谢

修改

我已经提出了一个足以解决问题的简单解决方案,如果它是最好的,那就不知道了。

struct node
{
    void *data;
    node *next;
}

我添加了一个"描述符" node,包含第一个节点的地址和有关类型的信息:

struct list_desc
{
    node *list;
    short int type;
}

我会将它与一些像

这样的宏一起使用
#define __data_type1 10
#define __data_type2 20

所以稍后我可以比较if(struct.type == __data_tipe1)等......

4 个答案:

答案 0 :(得分:4)

C不提供运行时类型信息。您必须自己添加此信息。有两种基本方法(假设C99或C11):

您可以使用具有匿名联合的结构(可能):

struct Node {
    enum {
        OBJ_TYPE_A,
        OBJ_TYPE_B
    } type;
    union {
        struct NodeA a;
        struct NodeB b;
    };    // anonymous, if a name is added, you have an additional field name
};

...

struct Node *node = ...;

if ( node->type == OBJ_TYPE_A ) {

    node->a.a_field = whatever;

...

缺点是你必须在一个地方定义联合,而不能在另一个模块中扩展它。

更好的方法是使用匿名结构构建一个真正的类层次结构:

struct Node {
    enum {
        OBJ_TYPE_A,
        OBJ_TYPE_B
    } type;
    struct Node *next;
};

struct NodeA {
    struct Node;    // base class, first field!
    int a_field;
};

struct NodeB {
    struct Node;    // base class, first field!
    float b_field;
};

void take_node(struct Node *node)
    // takes a generic pointer to the base-class
{

    if ( node->type == OBJ_TYPE_A ) {
        struct NodeA *a_node = (NodeA)node;
        a_node->a_field = whatever;
    } else if ...

    ...

}

// until here that is normal C99

int main(void)
{
    struct NodeA anode = { .type = OBJ_TYPE_A, .a_field = 42 };
    struct NodeB bnode = { .type = OBJ_TYPE_B, .b_field = 4.2 };
    take_node((Node *)&anode);    // standard: inhibits type checking
    take_node(&anode);    // plan9-extension: no cast required
    take_node(&bnode);    // plan9-extension: no cast required
}

Pro在创建新的子结构时不需要扩展基本结构(它不依赖于子结构)。匿名结构允许创建直接子项的子项和访问字段,如OOP中所期望的那样(没有字段说明符链:child1_1_1_ptr->child1_1.child1.base.base_field,而只是child1_1_1_ptr->base_field)。

take_node的后两次调用使用gcc C-extension -fplan9-extensions。这样可以避免在仍然启用类型检查(基类或子类)的同时强制转换为基类。这是向OOP迈出的一大步。

这可以扩展到全尺寸OOP方法,包括虚拟方法。但是,使用像C ++这样真正的OOPL变得更容易了。

答案 1 :(得分:3)

C不包含有关指针指向的运行时信息。您可以创建一个包含类型字段和联合的结构,其中包含您要存储的任何内容。

enum node_type {
    NODE_TYPE_STRING,
    NODE_TYPE_INT,
    NODE_TYPE_DOUBLE,
    NODE_TYPE_OTHER_STRUCT
};

struct other_struct {
    // define some fields
};
struct node_data {
   enum node_type type;
   union {
       char *string;
       int i;
       double d;
       struct other_struct other;
    } data;
};

答案 2 :(得分:2)

C是一种编译语言。有关"类型"的信息结构或任何其他变量只存在于编译时,而不是运行时。如果你需要多态性,你必须自己实现它。

一种常见的方法是使一组结构的第一个元素成为一个标识符。一个数字(可能是信息类型表的索引),或类似信息结构的地址。然后你可以为这些结构中的任何一个分配指针,并检查第一个字段以决定如何处理它。

答案 3 :(得分:1)

您如何看待这个:

typedef enum tag_ElementType
{
    ElementA,
    ElementB
} en_ElementType;

typedef struct tag_Container
{
    en_ElementType ElementType;
    void *pData;
} st_Container;

在这种情况下,您的结构将如下所示:

typedef struct tag_node
{
    st_Container the_data;
    struct tag_node *next;
} st_node;