当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?
MSDN 认为匿名结构在C++中是非标准的:
Microsoft C扩展允许您在另一个结构中声明结构变量而不为其指定名称.这些嵌套结构称为匿名结构.C++不允许匿名结构.
您可以访问匿名结构的成员,就好像它们是包含结构中的成员一样.
我被告知这个功能不一定只是创建一个未命名的结构,但我不能看到标准措辞的区别.
C++ 11说:
[C++11: 9/1]:[..]一个类说明符,其类头省略了class-head-name,定义了一个未命名的类.
并为缺少名称的类型定义提供完整的语法结构.
C++ 03缺少这种明确的措辞,但同样表明identifier类型定义中的类型是可选的,并在9.4.2/5和中引用了"未命名的类" 3.5/4.
union通过@ecatmur(/sf/answers/2209049671/)通过引用以下位来讨论关于类型惩罚的大部分未实现或实现定义的性质,关于标准的豁免 -布局structs具有成员类型的"公共初始序列":
C11(6.5.2.3结构和联合成员 ; 语义):
[...]如果一个联合包含几个共享一个共同初始序列的结构(见下文),并且如果联合对象当前包含这些结构中的一个,则允许检查其中任何一个的公共初始部分.完整的工会类型的声明是可见的.如果对应的成员具有一个或多个初始成员的序列的兼容类型(并且对于位字段,具有相同的宽度),则两个结构共享 共同的初始序列.
C++ 03([class.mem]/16):
如果POD-union包含两个或多个共享公共初始序列的POD结构,并且如果POD-union对象当前包含这些POD结构中的一个,则允许检查它们中的任何一个的公共初始部分.如果对应的成员具有一个或多个初始成员的序列的布局兼容类型(并且对于位字段,具有相同的宽度),则两个POD结构共享共同的初始序列.
这两个标准的其他版本有相似的语言; 从C++ 11开始,使用的术语是标准布局而不是POD.
由于不需要重新解释,这不是真正的类型惩罚,只是应用于union成员访问的名称替换.C++ 17(臭名昭着的P0137R1)的提议使得这种语言明确地使用了"访问就像其他结构成员被提名一样"的语言.
但请注意粗体 - " 在任何地方都可以看到完整类型的联合声明 " - C11中存在的条款,但在2003年,2011年或2014年的C++草案中没有任何内容(几乎完全相同,但后来的版本取代了" POD"使用新术语标准布局).在任何情况下,在union任何C++标准的相应部分中都完全没有' 类型位的可见声明.
@loop和@ Mints97,这里 - /sf/answers/1997029261/ - 显示这一行在C89中也没有出现,首先出现在C99中,然后保留在C中(尽管如此,从来没有过滤过到C++).
[剪掉 - 看我的回答]
从那以后,我的问题是:
这是什么意思?什么被归类为"可见声明"?该条款是否旨在缩小 - 或扩大 - 这种"惩罚"定义行为的背景范围?
我们是否假设C++中的这种遗漏是非常慎重的?
C++与C不同的原因是什么?C++是否只是从C89"继承"了这个,然后决定 - 或者更糟,忘记 - 与C99一起更新?
如果差异是故意的,那么 …
比方说,我有一个struct RGB,我想创建struct RGBA,继承RGB:
struct RGB {
unsigned char r;
unsigned char g;
unsigned char b;
};
struct RGBA: RGB {
unsigned char a;
};
Run Code Online (Sandbox Code Playgroud)
两者都将用于读取未压缩的图像数据:
RGBA *pixel=static_cast<RGBA *>(image->uncompressed_data);
Run Code Online (Sandbox Code Playgroud)
问题:关于内存布局,这样安全struct RGBA吗?有人保证:
unsigned char a之后RGB struct(不是之前)struct RGB和参数来自struct RGBA?会有#pragma pack帮助吗?这都是关于继承期间的内存布局.
我们拥有经过数十年开发的大型 C 代码库。该代码的特点之一是对函数指针和伪继承的大量依赖。习语(如此处讨论的)如下所示:
typedef struct twod_ {
double x, y;
} twod;
typedef struct threed_ {
twod super;
double z;
} threed;
threed *point_3d;
twod *point_2d = (twod *)point3d;
Run Code Online (Sandbox Code Playgroud)
此时point_2d->x和point_3d->x是同一块内存。
我的问题是:
当然,“如果它没坏,就不要修理它”这句格言值得牢记。然而,目前这并没有真正帮助我们,所以我们认为我们可能需要更深入地重构......
谢谢!