提问人:Arek' Fu 提问时间:10/18/2023 更新时间:10/18/2023 访问量:85
将标准布局对象数组转换为元素数组
Casting an array of standard-layout objects to array of elements
问:
在 C++ 中,指向标准布局类型的指针指向指向 的任何成员的指针是合法的,可能使用 offsetof
宏。如果只有一个成员,则没有必要,这是合法的:reinterpret_cast
S
S
S
offsetof
struct S {
int x;
};
static_assert(std::is_standard_layout_v<S>);
void f(S s) {
// this is legal for standard-layout classes, offsetof the first member is zero
S *s0 = &s;
int *x0 = reinterpret_cast<int *>(s0);
}
但现在假设我有一个数组:S
S arr_s[10];
我可以合法地让数组衰减为指针
S *s0 = arr_s;
我可以合法地将指针投射到:int *
int *x0 = reinterpret_cast<int *>(s0);
这是否意味着我可以通过以下方式访问整个阵列?索引超过 0 是否合法?我很确定答案是否定的,因为可能有不止一个成员。但是,如果我们将自己限制在只有一个成员的情况下,我是否可以以某种方式合法地将数组视为数组?x0
x0
S
S
S
int
答:
我可以合法地将指针转换为 int *:
是的。
这是否意味着我可以通过 x0 访问整个阵列?索引 x0 超过 0 是否合法?
不。您可以通过 形成、取消引用和访问。也可以形成 ,但它将是 one-past-the-object 指针,并且不能被取消引用。不能形成指向任何其他索引的指针。从强制转换接收到的指向不属于数组的单个对象。此类情况被视为属于大小数组,并且指针算术仅在该数组中定义。x0+0
x0+1
int*
int
int
1
我很确定答案是否定的,因为 S 可能有多个成员。但是,如果我们将自己限制在 S 只有一个成员的情况下,我是否可以以某种方式合法地将 S 数组视为 int 数组?
不,类的布局完全没有影响,除了对于非标准布局类,它本身将无法按预期工作,甚至在索引处访问或任何指针算术(包括)都将是 UB,因为在这种情况下甚至不会导致指向对象的指针。然后,您将尝试访问与(指针删除的)表达式类型不相似的对象或对对象执行指针算术运算。reinterpret_cast
0
+0
reinterpret_cast
int
目前没有办法实现你想要的。
在 C++ 中,将指向标准布局类型 S 的指针reinterpret_cast指向指向 S 的任何成员的指针是合法的,可能使用 offsetof 宏。
从技术上讲,目前除了第一个元素之外,这是不可能的。但这是标准的缺陷。它目前没有正确指定应该生成指向对象表示的指针(这是唯一可以使用的方法)。此规范的细节将取决于哪些结构具有 UB,哪些没有。这并非直截了当。reinterpret_cast<unsigned char*>
offset
offsetof
所有这些都是在标准保证(C++ 或更高版本)方面。这在实践中是否会给编译器带来问题是一个不同的问题。在实践中(我认为),只要您确保满足所有对齐要求并且大小匹配,您就可以使用当前的编译器。请注意,类中只有一个成员并不能保证后者。最后可能仍然有填充。
是的,因为通过 x0 访问数组元素的合法性取决于 S 类型的属性。如果 S 只有一个成员,如提供的代码所示,则通过 x0 访问数组元素是合法的。这是因为 reinterpret_cast 有效地将 S 数组视为 int 数组。
但是,正如您提到的,此方法仅在 S 只有一个成员时才有效。
评论
short
long
int*