基于两个可能的结构的未知void指针的访问类型标志?

Lig*_*rms 6 c void-pointers octree

我目前在C中使用自己的八叉树.树将包含几十亿个对象,因此内存效率是关键.为了实现这一点,我目前使用一个带有标志和联合的结构,但我认为它不干净并且它浪费了内部节点的空间,因为我只需要一个8位标志但是为64位保留了内存指数.我的代码目前如下:

typedef struct _OctreeNode
{
    uint64_t location_code;
    union
    {
        uint8_t child_exists;
        uint64_t object_index;
    } data;
    uint8_t type;
} OctreeNode;
Run Code Online (Sandbox Code Playgroud)

我想把它分成两个不同的结构.一个叶节点和一个内节点.如下:

typedef struct _OctreeInnerNode
{
    uint64_t location_code;
    uint8_t child_exists;
    uint8_t type;
} OctreeInnerNode;

typedef struct _OctreeLeafNode
{
    uint64_t location_code;
    uint64_t object_index;
    uint8_t type;
} OctreeLeafNode;
Run Code Online (Sandbox Code Playgroud)

现在问题出现在我的无序地图上,基于位置代码的哈希值.它使用void指针,因此存储两个不同的结构不是问题.我知道有可能将标志作为第一个元素并取消引用指向flag数据类型的指针来派生类型,如下所示:

typedef struct _OctreeLeafNode
{
    uint8_t type;
    uint64_t location_code;
    uint64_t object_index;
} OctreeLeafNode;

void
func(void* node)
{
    uint8_t type = *(uint8_t*)node;
    if (type == LEAF_NODE) {
        OctreeLeafNode* leaf_node = (OctreeLeafNode*)node;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否有更清洁的方式.或者这不推荐?我怎么能处理结构和void指针的多种可能性?

提前致谢!

Afs*_*hin 5

这是一种常用的方法C.

但是只需将这些字段放在结构的开头(第一个字段)并且永远不要改变它们的位置.此外,您需要将它们保留在所有结构中.

此方法的常见示例是version结构中的字段(或type在您的情况下).您可以将它们保留在结构的开头,然后通过类似的方法检查结构版本.这样的事情:

struct _base {
    uint8_t ver;
};

#define TYPE_OLD 0
struct _a_old {
    struct _base info;
    uint8_t a;
};

#define TYPE_NEW 1
struct _a_new {
    struct _base info;
    uint8_t a;
    uint8_t b;
};
Run Code Online (Sandbox Code Playgroud)

现在,您可以通过将数据转换为struct _base检查ver字段来识别不同类型.

unsigned char* buf = ...
switch (((struct _base*)buf)->ver)
{
    case TYPE_OLD:
    {
        struct _a_old* old = (struct _a_old*)buf;
        // ...
        break;
    }
    case TYPE_NEW:
    {
        struct _a_new* old = (struct _a_new*)buf;
        // ...
        break;
    }
    default:
        // ...
}
Run Code Online (Sandbox Code Playgroud)