c - 如何检查C中的结构类型

标签 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;
}

然后我添加了一个“描述符”节点,其中包含第一个节点的地址和有关类型的信息:

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

我会将它与一些宏一起使用,例如

#define __data_type1 10
#define __data_type2 20

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

最佳答案

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

您可以(可能)使用带有匿名 union 的结构:

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;

...

缺点是您必须在一个地方定义 union 并且不能在另一个模块中扩展它。


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

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
}

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

take_node 的后两次调用使用 gcc C 扩展 -fplan9-extensions。这避免了转换为基类,同时仍然启用类型检查(基类或子类)。这已经是向 OOP 迈出的一大步。

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

关于c - 如何检查C中的结构类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31596341/

相关文章:

c - 指向 C 中结构表的指针

c - 如何使用 libcurl (或其他方式)从 HTTP 服务器检索文件?

c++ - pthread_exit(NULL);不工作

c - ALSA中period的含义

c - 这个星号是做什么用的?

c - main 的三个参数和其他混淆技巧

c - 仅在大括号范围内缩进代码是否常见?

c - 移动数组中的字符串位置

c - 如何根据 C 中的用户输入创建 n 个数组

c - 这些 typedef 用法有什么区别?