2017-05-26 43 views
1

我有以下结构类型:初始化匿名结构的,解决方法GCC 4.9

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; 
      }; 
     }; 
    }; 
}; 

有以下初始化:

#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)) } 

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

警告:缺少初始值设定的领域 '大小' '结构<匿名>'[-Wmissing场-初始化]

它如果我将初始化程序更改为此版本,则可行:

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

也就是说,显式地使用union和struct作为子聚合。

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

+0

试着用'-pedantic'编译。如果它不给你警告,你应该很好去。 –

+0

是的,我已经做到了,铿锵声3.5.0和gcc 6.3.0没有什么可抱怨的。仍然不确定在阅读[本答案]的标准报价后是否允许它(https://stackoverflow.com/a/5065829/2371524) –

+1

编译器没有拒绝它 - 它只发出警告。你应该认真对待,但这可能不成问题。如何编写一个简短的测试程序来检查对象是否按照预期初始化? –

回答

2

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

这有两个部分。首先,我们需要解决的是否有这样的会员可以在所有被初始化的问题,因为识别匿名结构和工会会员为特定类型的“无名成员”,并paragraph 6.7.9/9

除非明确说明否则,就本小节而言,结构体和联合体类型的未命名成员不参与初始化。

节6.7.9的其余部分(初始化)无处说什么,我会解释为明确应用于匿名结构和匿名工会成员自己,但我不认为其目的是为了防止初始化名为匿名成员的成员,尤其是考虑到他们被认为是包含结构或联盟的成员(见下文)。因此,我不解释标准禁止您尝试执行的初始化。

所以,是的,我读了C11以允许您的初始值设定项并指定它具有您想要的效果。特别是,该标准的paragraph 6.7.2.1/13部分说明了

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

你初始化满足约束在paragraph 6.7.9/7,即内部的代号指定当前对象的成员的名称(在你的情况下,struct PG_Bounds)。 6.7节的以下段落。9提供了初始化器的语义,并且我没有理由将它们解释为指定除了用您提供的值初始化整个对象之外的任何东西。

在这一点上,我重申,海湾合作委员会发布警告,不拒绝你的代码,在这种情况下,我认为警告是虚假的。我写了一个测试程序,例如我在评论中建议的那样,并且在C11模式下在gcc 4.8.5上尝试了它。尽管gcc发出的警告与您提出的警告相同(但仅限于启用-Wextra),但我能够证明您的初始化程序已将主题struct PG_Bounds的所有成员初始化为预期值。


如果你改变了初始化到使用嵌套括号括起初始化一个版本还观察到,GCC不会发出警告,并要求

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

对于段落6.7.9/9,这可能会被视为更成问题,所以从这个意义上讲,它可能更危险。我不确定是否有任何编译器实际上拒绝它或者用它做了错误的事情。我认为标准的意图是允许这个初始化器,但我更喜欢另一种形式,我自己。

+0

我确认约翰的观点,显然这个标准的意图是让匿名'struct'的字段像直接指定那样工作。 '-Wextra'通常具有虚假的警告,特别是关于'struct'字段的非初始化。 'struct'成员的默认初始化是C标准的一个重要特征,并且警告它只是反作用。 –