在C中维护指向两个相关类型的指针数组

在C中维护指向两个相关类型的指针数组,c,C,我的结构如下 struct things { BOOL_T is_copy; /* is false */ handle1 h1; handle2 h2; int n; void * memory; }; 有时我会在下面的结构中复制事物的对象 struct copy_of_things { BOOL_T is_copy; /* is true */ handle1 h1; /* I don't need h2 and n here */ void

我的结构如下

struct things
{
  BOOL_T  is_copy;  /* is false */
  handle1 h1;
  handle2 h2;
  int     n;
  void *  memory;
};
有时我会在下面的结构中复制
事物的对象

struct copy_of_things
{
  BOOL_T  is_copy; /* is true */
  handle1 h1; /* I don't need h2 and n here */
  void *  memory;  /* copied from things object and
                      things object allocates new memory */
  int     another_member;
};
此外,我在一个管理器中有一个结构数组,它保存了我程序中的所有
事物
copy\u事物
结构(称之为
struct things*things\u array[SIZE\u of\u array];
)。由于设计要求,我无法管理2个数组(数组类似于散列)。为了启用此功能,我将此数组的类型设置为
thing*
,并将
copy\u of_things
的类型更改如下

struct copy_of_things
{
  struct things ths;
  int    another_member;
};
现在我可以读取数组元素的
is\u copy
成员,并决定是将其解释为
事物
还是
复制事物

我觉得这不仅在内存方面效率低下,而且在外观上也很难看

解决方案2 我还计划使用数组的类型is
struct of type(is_copy)和一个union

struct things {
  BOOL_T  is_copy;
  union {
    struct {  /* is_copy = false */
      handle1 h1;
      handle2 h2;
      int     n;
      void *  memory;
    } t;
    struct {  /* is_copy = true */
      handle1 h1;
      void *  memory;
      int     another_member;
    } c;
};
但在回顾时,我发现这个设计也很难看

解决方案3我计划保留
BOOL\u T的副本
作为结构的第一个成员,并保留类型为
BOOL\u T
的数组。在阅读了
BOOL\u T
的内容后,我可以取消引用指向对象的指针或复制对象。我不确定这是否是一个好的解决方案,并提供了一个定义良好的行为(在更高的优化级别),因为同一地址被解释为不同的类型

问题 对于我的问题,有没有更好的解决方案可以移植到任何平台上

编辑
谢谢您的回答。因此,有两个建议的替代方案

  • 使用联合:这种方法的缺点是,复制需要更多内存。在我的例子中,事物的拷贝大小明显小于事物的拷贝大小。一种解决方法是将实际对象可以驻留的足够字节分配给alloc
  • 使用公共结构并使其成为
    copy\u of_things
    things
    的第一个成员。在这里,我将使用两种类型(struct common和struct things或struct copy of theu things)取消引用相同的内存位置。我不确定那会不会咬到我
  • 还有一个解决方案可以将两个结构的第一个成员保留为
    char is_copy;/*\如果不是副本,则为0,否则为非零
    ,仅以
    char*
    things*
    copy\u of\u things*
    的形式访问指针

  • 仍然是一个悬而未决的问题
    我在很多地方看到了解决方案2。严格的别名规则安全吗?是否有更好的解决方案来解决我的问题,因为代码将在各种编译器上编译。反向映射数组的大小很大,所以我避免使用增加反向映射大小的联合或解决方案。东西(和副本)的数量较少,因此可以在那里添加新的数据成员。

    您可以使用更紧凑的联合来共享这些结构的一些成员:

    struct things {
      BOOL_T  is_copy;
      handle1 h1;
      void *  memory;
      union {
        struct {  /* is_copy = false */
          handle2 h2;
          int     n;
        } t;
        struct {  /* is_copy = true */
          int     another_member;
        } c;
    };
    

    您可以使用更紧凑的联合体共享这些结构的一些成员:

    struct things {
      BOOL_T  is_copy;
      handle1 h1;
      void *  memory;
      union {
        struct {  /* is_copy = false */
          handle2 h2;
          int     n;
        } t;
        struct {  /* is_copy = true */
          int     another_member;
        } c;
    };
    

    在其他结构中拥有一个结构是模拟C中继承的常见方法。这里重要的是,公共结构应该包含“继承”层次结构中所有结构所共有的最小数据集,并且它必须始终是继承结构中的第一个成员

    关于包含公共成员,第一件重要的事情是,如果没有公共数据,那么结构是完全不相关的,没有必要将它们相互关联

    关于将结构放在第一位,另一件重要的事情是因为公共成员的偏移量将是相同的,并且您可以轻松地将指向较大结构的指针视为指向较小基础结构的指针


    例如,在前两个结构中,
    is_copy
    成员将根据指针指向的结构而具有不同的偏移量,因此在访问
    is_copy
    成员之前,您需要知道指针指向的结构,哪种类型的偏移量不符合您的目的

    另一种方法是将基础结构作为扩展结构中的一个成员放置,这就是我上面所说的


    然而,如果您只是使用这两种结构,并且永远不会扩展到更多,那么使用带有联合的版本可能是处理它的最佳方式



    至于可移植性,只要不在平台之间传输结构,也不为应用程序的不同部分使用不同的编译器,那么
    union
    版本是最可移植的源代码。“继承”方案将在所有类似PC的现代系统及其编译器上运行,并且已经运行了很长时间,但不能保证它能在所有系统和所有编译器上运行(如果您计划将代码移植到具有奇怪硬件和编译器的罕见系统上,您可能需要注意“继承”计划不会起作用(因为规模很小,大多数人在一生中都不会接触到这样的系统。)

    在其他结构中拥有一个结构是模拟C中继承的常见方法。这里重要的是,公共结构应该包含“继承”层次结构中所有结构共有的最小数据集,并且它必须始终是继承结构中的第一个成员

    关于包含公共成员,第一件重要的事情是,如果没有公共数据,那么结构是完全不相关的,没有必要将它们相互关联

    关于将结构放在第一位,另一件重要的事情是因为公共成员的偏移量将是相同的,并且您可以轻松地将指向较大结构的指针视为指向较小基础结构的指针


    比如说,,
    struct thing_array_item
    {
       struct things *obj1;
       struct copy_of_things *obj2;
    };
    
    struct things
    {
        BOOL_T is_copy;
        union
        {
            struct
            {
                handle1 h1;
                handle2 h2;
                int     n;
                void * memory;
            } * t;
            struct
            {
                handle1 h1;
                void * memory;
                int another_member;
            } * c;
        };
    };
    
    if (mything.is_copy)
    {
        mything.c->another_member;
    } else {
        mything.t->n;
    }
    
    if (mything.obj_type == copy)
    {
        ((struct copy_of_things) mything.object)->another_member;
    } else {
        ((struct things) mything.object)->n;
    }
    
    struct common {
      handle1 h1;
      void *  memory;
    };
    
    struct things
    {
      handle2 h2;
      int     n;
      struct common cmn;
    };
    struct copy_of_things
    {
      BOOL_T  is_copy; /* is true */
      int     another_member;
      struct common cmn;
    };