为什么C ++不允许匿名结构?


92

一些C ++编译器允许匿名联合和结构作为标准C ++的扩展。这是一种语法糖,偶尔会很有帮助。

有什么理由阻止它成为标准的一部分?有技术障碍吗?哲学的?还是只是不足以证明其合理性?

这是我正在谈论的示例:

struct vector3 {
  union {
    struct {
      float x;
      float y;
      float z;
    };
    float v[3];
  };
};

我的编译器会接受这一点,但警告“无名结构/联合”是C ++的非标准扩展


3
显然,您的意思有些混乱。您能否提供一个由于编译器扩展而只能编译的代码示例?
罗伯·肯尼迪

72
请注意,有两个概念听起来很相似,但有很大不同:未命名的结构匿名的结构。第一个是C ++支持的一个struct { int i; } a; a.i = 0;(类型没有名称)。第二是这一个,其中C ++不支持:struct { int i; }; i = 0;(类型没有名称,并将其逃逸到周围范围)。但是,C ++ 确实支持未命名和匿名联合
Johannes Schaub-litb 2010年

这看起来像是相当有趣的VMMLib矢量库。我认为问题在于该联合包含一个未命名的结构,但是我不确定。
greyfade 2010年

1
FWIW它的“anonmyous”,而不是“无名”,和工会正在为litb表示支持。stackoverflow.com/q/14248044/560648
2013年

1
@AdrianMcCarthy:很好(FSVO是“很好”;讨厌的编译器是神秘的),但是恰好“未命名”是一个不相关的标准概念。
Lightness Races in Orbit

Answers:


50

正如其他人指出的那样,标准C ++允许使用匿名联合,但不允许使用匿名结构。

这样做的原因是C支持匿名联合,但不支持匿名结构*,因此C ++支持前者以实现兼容性,但不支持后者,因为不需要兼容性。

此外,C ++中对匿名结构的使用很少。您演示使用,有包含三个浮筒可以由被称为或是结构.v[i],或者.x.y.z,我相信在不确定的行为在C ++中。C ++不允许您写入工会的一个成员,例如.v[1],然后再从另一个成员进行读取,例如.y。尽管执行此操作的代码并不罕见,但实际上定义不明确。

C ++针对用户定义类型的功能提供了替代解决方案。例如:

struct vector3 {
  float v[3];
  float &operator[] (int i) { return v[i]; }
  float &x() { return v[0]; }
  float &y() { return v[1]; }
  float &z() { return v[2]; }
};

* C11显然添加了匿名结构,因此将来对C ++的修订可能会添加它们。


2
+1:我的示例依赖于C ++中的未定义行为-编写问题时,我并没有意识到这一点。
阿德里安·麦卡锡

2
“ C ++不允许您先写union [...]的一个成员,然后再从另一个成员读取”- 除非所述成员是标准布局对象,并且共享其成员的公共初始序列否则您会在所述公共初始序列中重新写入/读取成员。这允许的(即定义)。
underscore_d

5
@underscore_d:是的,如果类型是具有公共初始序列的标准布局。但是,结构永远不能以这种方式与数组混叠,因为C ++的“公共初始序列”规则指出,公共初始序列只能在struct之间。没有提到数组,因此它们不能像这样别名。
Nicol Bolas

@NicolBolas哦,哈哈-相信我-我希望很多次将数组和其他基元包含在此津贴中!但是我对此没有考虑太多实际可能的限制,因此它可能并不像现在看起来那么简单。我的意见是比较一般,但可能我-我冒着被遗漏在暗示我以为阵列,包括在此,十分感谢并称英寸
underscore_d

“这样做的原因是C支持匿名联合,但不支持匿名结构。” –不。您的脚注明确说明您在这里谈论的是C99或更早版本。术语“匿名联合”在C99标准中没有出现。GCC在诊断中(带有-std = c99 -pedantic选项)声称“ ISO C99不支持未命名的结构/联合”。除了未命名的位域外,该标准未提及任何有关未命名成员的信息。我不能完全确定struct-declaration是否为声明,但如果是,则匿名联合是6.7p2的约束违例,充其量是未定义的。

21

我会说,您可以vector3仅使用union

union vector3 {
  struct { float x, y, z; } ;
  float v[3] ;
} ;

当然,匿名结构 MSVC的扩展。但是ISO C11现在允许它,而gcc允许它,Apple的llvm编译器也允许

为什么在C11中而不在C ++ 11中?我不确定,但实际上大多数情况下(gcc ++,MSVC ++和Apple的C ++编译器),C ++编译器都支持它们。


1
+1获取更新的信息。我拥有外部结构的原因是因为“真实代码”也具有方法。
阿德里安·麦卡锡

联合不能做的唯一事情就是拥有静态数据成员,或者使用继承
bobobobo 2012年

2
谢谢。我从来没有像一个struct或class那样使用过工会。
阿德里安·麦卡锡

我知道默认情况下,Sun Studio在C ++ 11之前不支持匿名结构。如果您正在编写跨平台代码,并且编译器未升级到C + 11,则不要使用匿名结构。
irsis

6

不明白你的意思。C ++规范的9.5节,第2节:

形式的并集

union { member-specification } ;

被称为匿名联合;它定义了一个未命名类型的未命名对象。

您也可以执行以下操作:

void foo()
{
  typedef
  struct { // unnamed, is that what you mean by anonymous?
    int a;
    char b;
  } MyStructType; // this is more of a "C" style, but valid C++ nonetheless

  struct { // an anonymous struct, not even typedef'd
    double x;
    double y;
  } point = { 1.0, 3.4 };
}

并非总是非常有用...尽管有时在讨厌的宏定义中很有用。


11
-1是因为它说它定义了一个匿名结构。请参阅上面有关该问题的评论-您正在定义一个未命名的结构,而不是一个匿名的结构。
Johannes Schaub-litb

1

工会可以是匿名的;工会可以是匿名的。参见标准9.5第2段。

您认为匿名结构或类实现的目的是什么?在推测为什么某些东西不在标准中之前,我想知道为什么应该这样做,而且我看不到匿名结构的用途。


1

基于编辑,注释和MSDN这篇文章:Anonymous Structures,我冒昧猜测-它与封装的概念不太匹配。我不希望一个类的成员会与我的类名称空间发生混乱,而不仅仅是添加一个成员。此外,对匿名结构的更改可能会在未经允许的情况下影响我的班级。


1
由于创建匿名struct / unions的方式(特殊的内联语法只能被宏隐藏,因此无法隐藏),对于使用的某些成员是匿名成员,您不会感到惊讶。因此,我认为这种推理没有任何意义。实际的原因是,匿名联合用C ++的支持,因为只有C兼容性。C不支持匿名结构(直到C11),因此C ++也不支持。
bames53 2012年

1

您的密码

union {
  struct {
    float x;
    float y;
    float z;
  };
  float v[3];
};

就好像

union Foo {
   int;
   float v[3];
};

这肯定是无效的(在C99及更高版本中)。

原因可能是简化解析(在C语言中),因为在这种情况下,您只需要检查struct / union主体是否只有“ declarator语句”,例如

Type field;

就是说,gcc和“其他编译器”支持未命名字段作为扩展。

编辑:现在,C11(§6.7.2.1/ 13)中正式支持匿名结构。


5
从解析的角度来看,我认为这union { ... }与没什么不同struct { ... }。前者有效,但后者无效。
Johannes Schaub-litb 2010年

3
鉴于C ++通常很难解析,我怀疑标准提交不允许未命名的结构和联合只是为了简化解析。
Adrian McCarthy

@Adrian:我说的是C,不是C ++。C ++采用C的语法并对其进行扩展。可能是C ++的创建者认为不需要允许未命名的struct / union成员,这样他们才不会弄混语法的这一部分。
kennytm'2

@Adrian,关于Adrian的要点,我始终认为Bjarne和工作人员不会担心“实施太难”
bobobobo 2010年

C和C ++都支持未命名的联合,因此union { ... };无效的注释不正确。
bames53
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.