在结构联合

时间:2017-09-11 12:20:45

标签: c struct unions memory-alignment pointer-conversion

我有三个共享第一个字段和第一个字段名称的结构:

struct TYPEA {
  char *name;
  int x,y;   /*or whatever*/
};

struct TYPEB {
  char *name;
  float a[30]; /*or whatever*/
};

struct TYPEC {
  char *name;
  void *w,*z; /*or whatever*/
};

如果我没记错的话,结构的第一个字段需要从与结构本身相同的地址开始。

这让我想知道联盟是否也是如此:

union data {
  struct TYPEA;
  struct TYPEB;
  struct TYPEC;
};

union data *p = function_returning_a_sane_default_for_union_data();
printf("%s", (char*) p);

我有两个问题:

  1. 是标准要求的工会 总是把他们的内容放在同一个地址?
  2. 如果结构都有相同的结果,它会工作吗? fiels,只是名字不同?

1 个答案:

答案 0 :(得分:2)

structunion的第一个元素保证与struct´/联合本身具有相同的地址值。显然它的类型不一样!

对于您的使用,您不需要演员表,实际上应该避免使用:

  

6.5.2.3p6:为了简化联合的使用,我们做了一个特殊的保证:如果一个联合包含几个共享一个共同初始序列的结构(见下文),并且如果联合对象当前包含这些结构中的一个,允许检查其中任何一个的公共初始部分,其中可以看到完整类型的联合的声明。 ...

所以你可以(见下文)

printf("%s", p->name);

(注意:您对未命名的union成员的使用不是标准的编译。它是(非常有用的)gcc扩展名(-fms-extensions,至少也得到MSVC的支持)。)< / p>

但是:您问题中的代码是错误的。您必须为每个联合成员命名,或者为每个成员指定类型声明符。但是,如果使用相同的第一个成员,它将不会被打开,因为这些未命名成员的名字必须是唯一的(他们应该如何单独访问它们?)。所以这不会真的奏效。你可以做的是:

union data {
    struct TYPEA typea;
    struct TYPEB typeb;
    struct TYPEC typec;
};

printf("%s", p->typea.name);

即使struct目前包含TYPEB值。

另一种更明确的方法是将union打包成struct

struct TypeA {
    int x,y;
};

...

struct data {
    char *name;
    union {
        struct TypeA;
        struct TypeB;
        struct TypeC;
    };
};

这也在两个级别使用gcc扩展名:外部structunion。因此,它需要所有可能路径的唯一名称。如果您想要100%兼容,请像上面一样命名每个成员并使用访问的完整路径。

注意:我从name的内部struct移除了union成员,并将其移至外部struct。我也换了名字。 C中唯一被广泛接受的命名约定是仅对宏使用全大写。