【问题标题】:initialization of anonymous structures or unions in C1XC1X 中匿名结构或联合的初始化
【发布时间】:2011-07-01 02:48:23
【问题描述】:

我有以下问题:如何根据当前的C1X draft 正确初始化匿名结构(或联合)?这合法吗:

struct foo {
    int a;
    struct {
        int i;
        int j;
    };
    int b;
};

struct foo f = { 1, 2, 3, 4 };
struct foo g = { 1, { 2 }, 3 };

在 GCC 中,g.j == 0g.b == 3,而在 tcc 中 g.j == 3g.b == 0。目前的草案说:

“[...]结构和联合类型对象的未命名成员不参与初始化。结构对象的未命名成员即使在初始化后也具有不确定的值。”。

这真的是真的吗?不是

struct foo h = { 0 };

应该将 所有 成员设置为 0?

非常感谢!

更新

由于匿名成员似乎只在混合结构/联合时才有用,如何正确初始化它:

struct bar {
    int tag;
    union {
        double d;
        int i;
    };
};

?这会在 gcc

struct bar a = { .tag = 1, .i = 42 };

这会在 clang 和 tcc 中产生错误,但在 gcc 和 icc 中有效:

struct bar b = { .tag = 1, { .i = 42 } };

第二个是否违反标准?

【问题讨论】:

  • 重新更新:如果我对标准的解释是正确的,那么第二个例子确实是违规的:在.tag = 1 之后,当前对象(参见 6.7.9 §17)将与匿名联合的第一个成员double d,不能用{ .i = 42 }初始化...

标签: c standards anonymous structure c11


【解决方案1】:

我还没有阅读草稿,我很确定未命名的成员和匿名成员是不同的。无名会是这样的

struct foo {
    int bar:1; /* named */
    int :31;   /* unnamed */
};

【讨论】:

  • 是的,未命名与匿名不同,但未命名的 structunion 成员被称为匿名:“结构类型的未命名成员,没有标签称为匿名结构;没有标签的联合类型的未命名成员称为匿名联合。匿名结构或联合的成员被认为是包含结构或联合的成员。如果包含结构或联合,则递归适用也是匿名的。”
  • @jmuc:如果匿名结构或联合的成员“被认为是包含结构或联合的成员”,那么在我看来,虽然匿名结构或联合是“未命名的” , 它的成员,作为包含结构或联合的成员,被命名为...
【解决方案2】:

可以初始化结构中具有名称的所有成员。您只是不能像这样初始化中间结构。但是

struct foo f = { .a = 1, .i = 2, .j = 3, .b = 4 };

应该这样做。

【讨论】:

  • 谢谢!但是如果没有使用指定的初始化器会发生什么,比如struct foo g = { 0, { 0 }, 1 };? GCC 用中间的零初始化匿名结构,但仅在使用大括号时。这符合标准吗?
  • @jmuc:我认为@Christoph 的回答是正确的,我认为这不符合未来的标准,因为它说基本上周围的匿名部分将被忽略所有访问。另一方面,你不能抱怨 gcc 不符合 C1x,他们不会假装,不是吗?
【解决方案3】:

fh 应该正确初始化所有成员,因为 ij 将被视为 struct foo 的成员(C1x 6.7.2.1 §13):

匿名结构的成员 或工会被视为成员 包含结构或联合的。

考虑到 C1x 6.7.9 §9,我认为 gcc 对 g 的初始化不正确:

除非明确说明 否则,为此目的 子条款对象的未命名成员 结构和联合类型的不 参与初始化。

§20 - 处理子聚合 - 不包含与该问题相关的明确声明,所以我最好的猜测是 §9 适用(但仅适用于聚合本身,成员!)。

底线是匿名子聚合不作为单独的对象存在,即 tcc 的行为应该是正确的......

我对这个问题的看法的示例代码:

struct foo
{
    struct bar { int i; }; // (1) unnamed, but tagged, ie *not* anonymous
    struct { int j; };     // (2) unnamed, but anonymous
    struct { int k; } baz; // (3) named, but not tagged
};

(1) 不参与初始化,(2) 像 struct foo 有一个名为 j 的附加成员一样初始化,(3) 初始化为常规子聚合。

如果我的解释是正确的,匿名结构只有包含在联合中才有意义:结构中的匿名结构与包含其他成员的平面结构没有区别。

【讨论】:

  • 谢谢!所以我可能应该向 GCC 提交错误报告(尽管他们可能不想破坏旧代码)。由于允许在常量(非聚合)初始化器周围添加大括号,因此这两个应该相同:struct foo f = { 0, { 0 }, 1 };struct foo f = { 0, 0, 1};?
  • @jmuc:据我所知,是的;但是,联系 ISO 工作组可能是个好主意——第 6.7.9 节应明确地或至少作为示例处理匿名子聚合...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-21
相关资源
最近更新 更多