在 C 语言中具有自引用结构的内存体系结构



>我有一个名为container的结构。
此结构有一个名为 void 的指针,名为obj_mem,它将指向一些分配的内存。
由于这个内存必须能够容纳不同的结构,我跟踪它包含的每个元素的地址和类型(adress_objtype_obj)以进行访问和转换。
我的container结构的最后一个属性是它有一个自引用child
因此,在运行时,用户可以创建容器的子项并向它们添加对象。

typedef enum tob{ //type of object
obj1, obj2, obj3, obj4 ...
}t_tob;
typedef struct obj1{
//declare some stuff
}t_obj1;
typedef struct obj2{
//declare some stuff
}t_obj2;
typedef struct obj3{
//declare some stuff
}t_obj3;
typedef struct obj4{
//declare some stuff
}t_obj4;
typedef struct container{
int                name_size;
char*              name;
int                nmbr_obj;
t_tob*             type_obj;
char*              adress_obj;
void*              mem_obj;
int                nmbr_child;
struct container*  child;
}t_container;

然后我有一个处理整个数据的函数:
它处理容器obj_mem中的对象。
然后遍历他的孩子并处理他们的对象。
然后遍历他孩子的孩子并处理他们的 对象
等。。。直到树的尽头。

问题:
我对编程很陌生,我不确定这是正确的方法。
这段代码会导致很多malloc调用,所以内存不会是连续的,这是个问题吗?
有没有更优雅的方式来做这种动态类型的事情?
你有没有书可以帮助我更多地了解这种内存架构?
如果这篇文章看起来有点模糊,我很抱歉,但这就是我现在的感觉。

谢谢你的帮助。

内存不会是连续的,这是个问题吗?

这不是问题,但会损害性能。

使用更好的内存局部性(连续内存而不是碎片内存)有助于 CPU 利用其缓存并最大限度地减少缓存未命中,这在性能方面可能是一件非常重要的事情。

但这并不是最重要的部分。您始终可以在稍后对其进行优化。最重要的部分是数据结构实际上做了它需要做的事情。

有没有更优雅的方式来做这种动态类型的事情?

可能,但我不确定你想做什么,所以我帮不了你。

通常,在编写动态类型系统时,对象的类型是对象的一部分,即:

struct my_object_s {
unsigned int type;
/* common type data*/
struct vtable_s * vtable;
};
struct my_string_s {
struct my_object_s header;
size_t len;
char str[];
}

这允许对象独立于其容器。

你有没有书可以帮助我更多地了解这种内存架构?

我在互联网上阅读了大部分我所知道的内容(我确实有几本书,但其中没有多少是硬件架构)。

编辑(回答评论)

您可以在此处找到有关使用 C 进行面向对象编程的更全面的信息。作者已经做了大量的工作来解释这些概念,在创作动态类型时经常使用这些相同的想法(部分或全部)。

例如,通过拥有虚拟函数表,可以完全避免强制转换。

另一方面,当您的类型集有限时,通常使用 switch 语句。

enum my_type_enum {
/** A simple flag object object (`my_object_s`) for NULL. */
MY_NULL,
/** A simple flag  object (`my_object_s`) for OK. */
MY_OK,
/** A simple flag object (`my_err_s`) that indicates an error. */
MY_ERR,
/** A Number object object (`my_number_s`). */
MY_NUMBER,
/** A String object (`my_string_s`). */
MY_STRING,
/** An Array object object (`my_array_s`). */
MY_ARRAY,
};
typedef struct { enum my_type_enum type; } my_object_s;
typedef struct {
my_object_s header;
size_t len;
char str[];
} my_string_s;
void example_usage(my_object_s *obj) {
switch (obj->type) {
case MY_STRING:
printf("String: %s", ((my_string_s *)obj)->str);
break;
default:
printf("whatever...");
}
}

请注意,通过将my_object_s作为每种类型的标头,您可以安全地访问标头数据,就像指向对象的任何指针都是my_object_s *一样,这样您就可以识别它的基础类型。

如果你的容器必须保存一个数据树,那么以某种形式几乎需要一个这样的结构。真正看起来很奇怪的一件事是,您的对象成员类型是一个指针,通常是一个简单的值。

最新更新