是否可以在UNION下动态选择2种结构中的一种?

时间:2016-12-16 13:51:20

标签: c

这个问题与C语言概念有关。

现有结构:

struct parent{
    char c[4];
    float f;
    double d;
    int flag;

    struct child_old
    {
        int i;
        float l;
    }c1;
}

我想在父级下添加一个新结构(让我们调用它 - child_new)。 我根据场景一次只使用一个子结构。不是一次两个。 所以我可以将它们放在UNION下。

修改结构:

struct parent{
    char c[4];
    float f;
    double d;
    int flag;

    union{
        struct child_old
        {
            int i;
            float j;
        }c1;

        struct child_new
        {
            int i;
            float j;
            char c[32];
            double d;

        }c2;
    }UU;
}

这里我的要求是,基于struct member“flag”值(0/1),我需要决定我需要使用哪个子结构。

这是因为:

  1. 我父类结构类型的文件系统中存储了大量数据。阅读时应该没有任何问题。
  2. 在使用child_old时,我不想消耗child_new所需的额外空间。
  3. C可以吗? 或者有解决方案吗?

4 个答案:

答案 0 :(得分:4)

你所写的内容很好,你会用以下内容来消费它:

switch(p.flag) {
   case CHILD_OLD:
       // work with p.c1
       break;
   case CHILD_NEW:
       // work with p.c2
       break;
} 

但是,对于联盟中最大的成员,您的完整结构总是足够大。所以当你使用c1时,你仍然有足够的空间来分配c2。但是,至少你每次都没有分配sizeof(c1) + sizeof(c2)

如果你真的想根据每个记录使用的变量分配更多或更少的空间,你需要在结构中放置一个指针,并为子元素动态分配一个单独的记录。

所有这些都意味着,如果您从磁盘读取字节数组,然后将它们转换为结构:

  parent *p = (parent*) addressOfSomeDataReadFromAFile;

(不是一个好主意,但在野外并不罕见)

...然后使用union技术扩展parent结构通常不起作用。您的现有文件将表示记录的字节数少于新结构。

答案 1 :(得分:1)

鉴于您的要求

  
      
  1. 在使用child_old时,我不想消耗child_new所需的额外空间。
  2.   

你不能使用工会。

Per 6.7.2.1结构和联合说明符the C Standard第16段:

  

联合的大小足以包含其中最大的一个   成员。

因此,联盟的大小将是最大成员的大小。

另请注意,正如评论中所指出的,更改联合也可能会影响包含该联合的任何结构的其他元素的填充/对齐。

答案 2 :(得分:0)

这是可能的,但它既不漂亮也不有效。使用联合存储不同类型的无关数据被认为是不好的做法。正如已经提到的那样,大小将是联盟中最大的成员,因此它也不具有内存效率。

相反,这是一个更明智的解决方案:

struct parent {
    char c[4];
    float f;
    double d;
    int flag;

    void* data;
}

...

struct parent x;
x.data = malloc(sizeof(struct child_old));
struct child_old* co_ptr = x.data;
co_ptr->i = ...;

这里void*指向在别处分配的实际数据。您还需要一些方法来跟踪存储在那里的数据类型。

答案 3 :(得分:0)

它很难看但它有效。

#include <sys/stat.h>
#include <fcntl.h>

enum Type {
  A,
  B,
};

struct Base {
  enum Type type;
};

struct A {
  char foo[4];
};

struct B {
  char bar[8];
};

struct BaseA {
  struct Base base;
  struct A a;
};

struct BaseB {
  struct Base base;
  struct B b;
};

int main(void) {
  int fd = open("foo.bar", O_RDONLY);
  if (fd == -1) {
    return 1;
  }

  union {
    struct Base base;
    struct BaseA base_a;
    struct BaseB base_b;
  } buffer;
  if (read(fd, &buffer.base, sizeof buffer.base) != sizeof buffer.base) {
    return 1;
  }

  if (buffer.base.type == A) {
    if (read(fd, &buffer.base_a.a, sizeof buffer.base_a.a) !=
        sizeof buffer.base_a.a) {
      return 1;
    }
  } else if (buffer.base.type == B) {
    if (read(fd, &buffer.base_b.b, sizeof buffer.base_b.b) !=
        sizeof buffer.base_b.b) {
      return 1;
    }
  } else {
    return 1;
  }
}

你可以在if语句中做你想做的事。在数组中添加每个Base_A,在另一个数组中添加所有Base_B

如果您不想填充,请使用#pragma pack(n)