问题标签 [standard-layout]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - 使用 POD-struct 的 reinterpret_cast 理解代码示例
我找到了一些代码,并想确保我正确理解了这一点。用例是由值数组表示的打包图像。在本例中,三个值代表一个像素。
我找到的代码是这样的:
正如我从阅读POD 和标准布局中了解到的那样,我认为代码示例是有效的,因为我们只使用了 Pixel 的第一个成员?然后将 Pixel 替换为
会导致未定义的行为吗?
编辑:我使用 cuda 并找到了另一个示例:将无符号字符指针(一个数组)转换为 uchar3 指针。uchar3 类型定义等于第二个像素定义。这是否意味着第二个也有效?还是这仅适用于 nvcc 编译的代码?如果第二个像素定义是有效的,那为什么?
编辑:为了进一步强调代码试图做什么,我重命名了上面的一些字段:我有一个原始数据数组。在我的情况下,这是一个打包的图像。我想要一种访问像素及其值的好方法。所以我可以做这样的事情:
我已经看到在 cuda 中使用它的代码并且它有效,但我想知道它是否总是好的,因为我读到的关于 POD 的内容似乎没有涵盖它。我只是错过了关于 POD 的一些东西,还是这可能会失败?
编辑:是否有区别:
我认为第二个应该是合法的,因为对于 POD 类型,第一个成员变量与对象具有相同的地址?
编辑:我从答案中得到的是:在我提到的所有情况下都是 UB。那么要走的路将是一个随机访问迭代器,它给我我想要的访问权限。
c++ - 标准布局和尾部填充
David Hollman 最近在推特上发布了以下示例(我稍微简化了):
您可以在 godbolt 上检查 clang 中的布局,发现大小更改的原因是,在 中FooBefore
,成员value
被放置在偏移 16 处(保持 8 的完全对齐FooBeforeBase
),而在 中FooAfter
,成员value
被放置在偏移 12 处(有效地使用FooAfterBase
的尾部填充)。
我很清楚这FooBeforeBase
是标准布局,但FooAfterBase
不是(因为它的非静态数据成员并不都具有相同的访问控制,[class.prop]/3)。但是FooBeforeBase
' 是需要这种填充字节的标准布局是什么?
gcc 和 clang 都重用FooAfterBase
了 的填充,最终以sizeof(FooAfter) == 16
. 但 MSVC 没有,以 24 结尾。是否有按照标准要求的布局,如果没有,为什么 gcc 和 clang 会这样做?
有一些混乱,所以只是为了澄清:
FooBeforeBase
是标准布局FooBefore
不是(它和基类都有非静态数据成员,类似于E
本例)FooAfterBase
不是(它具有不同访问权限的非静态数据成员)FooAfter
不是(出于上述两个原因)
c++ - 为什么标准布局类的成员必须具有相同的访问控制?
引用[class.prop]/3中的标准:
如果满足以下条件,则S 类是标准布局类:
- 对所有非静态数据成员具有相同的访问控制,
我的理解(也许我错了)一直是 C++ 访问控制不会以任何方式影响类的物理布局——它们纯粹是一种增强封装的编译时机制。(或者换句话说,将成员从私有更改为公共并不是 ABI 破坏性更改。)
如果是这种情况,那么标准布局类的这种限制的原因是什么?
c++ - 具有原始类型的单个数组成员的标准布局结构的保证内存布局
考虑以下简单结构:
我的问题是:
假设一个平台float
是 32 位 IEEE754 浮点数(如果这很重要),C++ 标准是否保证预期的内存布局struct A
?如果不是,它保证什么和/或执行保证的方法是什么?
通过预期的内存布局,我的意思是结构占用16*4=64
内存中的字节,每个连续的字节被数组中的4
一个字节占用。换句话说,预期的内存布局意味着以下测试通过:float
data
(offsetof
这里是合法的,因为A
是标准布局,见下文)
万一这让您感到困扰,测试实际上通过gcc 9 HEAD 的 wandbox。我从来没有遇到过一个平台和编译器的组合可以提供这个测试可能失败的证据,如果它们确实存在,我很想了解它们。
为什么有人会关心:
- 类似 SSE 的优化需要一定的内存布局(和对齐,我在这个问题中忽略了它,因为它可以使用标准
alignas
说明符来处理)。 - 这种结构的序列化可以简单地归结为一个漂亮且可移植的
write_bytes(&x, sizeof(A))
. - 一些API(例如OpenGL,特别是glUniformMatrix4fv)期望这种精确的内存布局。当然,可以只传递指向
data
数组的指针来传递这种类型的单个对象,但是对于这些序列(例如,用于上传矩阵类型顶点属性),仍然需要特定的内存布局。
实际保证:
据我所知,这些是可以预期的struct A
:
- 这是标准布局
- 作为标准布局的结果,指向的指针
A
可以是reinterpret_cast
指向其第一个数据成员的指针(大概是?),即在第一个成员之前data[0]
没有填充。
标准未提供(据我所知)的两个剩余保证是:
- 原始类型数组的元素之间没有填充(我确信这是错误的,但我未能找到确认参考),
- 里面的数组后面没有填充。
data
struct A
c++ - POD 类型是否完全等同于普通的标准布局类型?
在 C++20 中,POD 的概念已被弃用,据说是因为它是琐碎和标准布局的无意义复合特征。但是, C++20 草案中对 POD 的定义并不完全是“既琐碎又标准布局”;实际上是:
POD 类是一个既是普通类又是标准布局类的类,并且没有非 POD 类(或其数组)类型的非静态数据成员。POD 类型是标量类型、POD 类、此类类型的数组或这些类型之一的 cv 限定版本。
换句话说,POD 类型不仅是普通布局和标准布局,而且递归也是如此。
这个递归要求是多余的吗?换句话说,如果一个类型既是平凡又是标准布局,那么它是否也会自动递归平凡和标准布局?如果答案是“否”,那么标准布局、普通类型无法成为 POD 的示例是什么?
c++ - C++20 是否取消了对类成员按升序排列的要求?
在 C++17 中有规范文本 [class.mem]/17:
分配具有相同访问控制(第 14 条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。未指定具有不同访问控制的非静态数据成员的分配顺序。
还有[class.mem]/24:
如果标准布局类对象有任何非静态数据成员,其地址与其第一个非静态数据成员的地址相同
这里有两个例子:
根据上述标准文本,C++17 保证&a.x < &a.y
, &a.y < &a.z
, 和&f.p < &f.r
(但不保证&f.p < &f.q
,因为F
不是标准布局,所以 class.mem/24 不适用)。
但是,在 C++20 最终工作草案 N4860 中,根据CWG 2404进行了更改。[class.mem]/17 已经变成了一个注释。但是,注释在 ISO 标准中是非规范性的(意味着编译器供应商可以忽略它们)。而且我找不到任何其他可能适用的文本。
我的问题是: C++20 是否仍然在某个地方指定(规范地)保证&a.y < &a.z
和/或&f.p < &f.r
?或者编译器现在是否有权在所有情况下重新排序类成员,除了标准布局类的第一个子对象?
假设 N4860 和已发布的标准之间没有进一步的变化,我猜。
c++ - 将 POD“合并”为一个
有没有办法在它们之间组合(或合并、聚合)POD?一种直观的解决方案:
除了,我们失去了一些东西:
我看到我们最终可能会在合并的基类之间出现一些歧义和冲突。但是将 POD 合并为一个会非常好。我试图达到的结果:
我在反思的领域吗?我应该最终使用宏吗?
c++ - 使用标准布局类型与其他语言交流
[注3:标准布局类对于与用其他编程语言编写的代码进行通信很有用。它们的布局在[class.mem]中指定。——尾注]
按照链接,我们从这里class.mem
开始找到有关标准布局类型布局的规则,但我不清楚它们如何使它们对与其他语言进行通信有用。这一切似乎都与布局兼容的类型和通用的初始序列有关,但我没有看到任何迹象表明这些兼容性要求会扩展为给定的实现。
我一直认为标准布局类型不能具有由实现强加的任意填充,并且必须遵循“直观”的布局,这将使它们易于从其他语言中使用。但我似乎找不到任何这样的规则。
这个注释是什么意思?我是否错过了任何强制标准布局类型至少在给定平台上保持一致的规则?
c++ - 不是标准布局的普通类,反之亦然
什么是 C++ 类的示例,它是一个简单的类但不是标准布局类?
反之亦然?(不是 Trivial 类的标准布局类)。