匿名结构的初始化,gcc 4.9的解决方法

时间:2017-05-26 13:46:44

标签: c gcc language-lawyer c11

我有以下结构类型:

    q)@/[d;;{0N!(x;y);x+y};3]1 1 1
    ((8 9;10;11 12);3)
    ((11 12;13;14 15);3)
    ((14 15;16;17 18);3)
    (1 2 3;4 5 6 7)
    (17 18;19;20 21)
    (13 14;15 16 17 18;19 20)

使用以下初始值设定项:

typedef struct PG_Point PG_Point;
struct PG_Point
{
    int x;
    int y;
};

typedef struct PG_Size PG_Size;
struct PG_Size
{
    int width;
    int height;
};

typedef struct PG_Bounds PG_Bounds;
struct PG_Bounds
{
    union
    {
        struct
        {
            PG_Point topLeft;
            PG_Size size;
        };
        struct
        {
            struct
            {
                int x;
                int y;
            };
            struct
            {
                int width;
                int height;
            };
        };
    };
};

根据我的理解,在中初始化匿名结构的字段是正确的,就好像它们是包含结构的直接字段一样?但是使用gcc 4.9.2,这会发出以下警告:

  

警告:缺少'struct< anonymous>'[-Wmissing-field-initializers]的字段'size'的初始值设定项

如果我将初始化程序更改为此版本,则可以正常工作:

#define PG_Point_init(ix, iy) {.x=(ix), .y=(iy)}
#define PG_Size_init(iwidth, iheight) {.width=(iwidth), .height=(iheight)}

#define PG_Bounds_init(ix, iy, iwidth, iheight) { \
    .topLeft=PG_Point_init((ix),(iy)), \
    .size=PG_Size_init((iwidth),(iheight)) }

也就是说,明确地将union和struct作为子聚合。

这是否允许?我不得不期望其他编译器拒绝这个吗?

1 个答案:

答案 0 :(得分:2)

  

根据我的理解,在c11中正确初始化匿名结构的字段就好像它们是包含结构的直接字段一样?

这有两个部分。首先,我们需要解决这些成员是否可以初始化的问题,因为Paragraph 6.7.2.1/13将匿名结构和工会成员识别为特定类型的"未命名成员"和{{3说

  

除非另有明确说明,否则就本子条款而言,结构和联合类型的对象的未命名成员不参与初始化。

第6.7.9节(初始化)的其余部分没有说明我将解释为显式应用于匿名结构和匿名工会成员本身,但我不认为意图是防止匿名成员的名为成员的初始化,特别是考虑到他们被认为是包含结构或联合的成员(见下文)。因此,我不解释标准禁止您尝试执行的初始化。

所以是的,我读了C11以允许你的初始化器,并指定它具有你想要的效果。特别是,标准paragraph 6.7.9/9部分地说

  

匿名结构或联合的成员被视为包含结构或联合的成员。如果包含的结构或联合也是匿名的,则递归应用。

因此,初始化程序满足paragraph 6.7.2.1/13中的约束,指定者指定当前对象成员的名称(在您的情况下为struct PG_Bounds)。第6.7.9节的以下段落介绍了初始值设定项的语义,我认为没有理由将它们解释为除了使用您提供的值初始化整个对象之外的任何其他内容。

此时,我重申gcc正在发出警告,而不是拒绝您的代码,在这种情况下,我认为该警告是虚假的。我编写了一个测试程序,例如我在你做的评论中建议的,并在C11模式下在gcc 4.8.5上尝试过。虽然gcc发出了相同的警告(但只启用了-Wextra),但我能够证明您的初始值设定项已将主题struct PG_Bounds的所有成员初始化为预期值。

您还注意到,如果将初始值设定项更改为使用嵌套括号括起初始值设定项的版本,则gcc不会发出警告,并询问

  

这是否允许?我不得不期望其他编译器拒绝这个吗?

就第6.7.9 / 9段而言,这可能被视为更有问题,因此从这个意义上讲,它可能更具风险。我不确定是否有任何编译器实际上拒绝它或使用它做错了什么。我认为标准的目的是允许这个初始化器,但我更喜欢另一种形式,我自己。