代码之家  ›  专栏  ›  技术社区  ›  soall

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

  •  0
  • soall  · 技术社区  · 8 年前

    我有一个结构名为 container .
    此结构有一个类型为void的指针,名为 obj_mem ,它将指向一些已分配的内存。
    由于这个内存必须能够保存不同的结构,所以我跟踪地址及其包含的每个元素的类型( adress_obj , type_obj )用于通道和浇铸。
    最后一个属性我的 容器 结构是指它有一个自引用 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\U内存 容器的。
    然后遍历他的子对象并处理它们的对象。
    然后遍历他的孩子的孩子并处理他们的 对象
    发射型计算机断层扫描仪。。。直到树的尽头。

    问题是:
    我对编程很陌生,我不确定这是不是正确的方式。
    这段代码将导致大量malloc调用,因此内存不会连续,这是问题吗?
    有没有更优雅的方式来做这种动态的事情?
    你有什么书可以帮助我学习更多关于这种内存架构的知识吗?
    如果这篇文章看起来有点模糊,我很抱歉,但这就是我现在的感受。

    谢谢你的帮助。

    2 回复  |  直到 8 年前
        1
  •  1
  •   Myst    8 年前

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

    这不是一个 问题 ,但这会影响性能。

    使用更好的内存位置(连续内存而不是碎片内存)有助于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进行面向对象编程的更全面的信息 here . 作者已经做了大量的工作来解释这些概念,并且在创作动态类型时经常使用这些相同的思想(部分或全部)。

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

    另一方面,当类型集有限时,通常使用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 * 通过这种方式,您可以识别它的基本类型。

        2
  •  1
  •   SoronelHaetir    8 年前

    如果您的容器必须保存数据树,则在某种形式上非常需要这种结构。有一件事看起来很奇怪,那就是对象成员的类型是指针,通常是一个简单的值。