Are*_* Fu 2 c++ arrays casting standard-layout
在 C++ 中,将指向标准布局类型的指针reinterpret_cast指向指向 的任何成员的指针是合法的,可能使用宏。如果只有一名成员,则没有必要,这是合法的: SSoffsetofSoffsetof
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);
}
Run Code Online (Sandbox Code Playgroud)
但现在假设我有一个数组S:
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);
}
Run Code Online (Sandbox Code Playgroud)
我可以合法地让数组衰减为指针
S arr_s[10];
Run Code Online (Sandbox Code Playgroud)
我可以合法地将指针转换为int *:
S *s0 = arr_s;
Run Code Online (Sandbox Code Playgroud)
这是否意味着我可以通过访问整个数组x0?x0索引超过 0合法吗?我很确定答案是否定的,因为S可能有不止一名成员。但是,如果我们将自己限制在只有一个成员的情况S,我可以以某种方式合法地将数组视为S数组int吗?
我可以合法地将指针转换为 int *:
是的。
这是否意味着我可以通过 x0 访问整个数组?索引 x0 超过 0 合法吗?
不需要。您可以通过 形成、取消引用和访问x0+0。您也可以形成x0+1,但它将是对象后一位指针,并且可能不会被取消引用。您无法形成指向任何其他索引的指针。您从强制转换中收到的指向不属于 数组一部分的int*单个对象。这种情况被视为属于一个大小的数组,并且指针算术仅在该数组内部定义。intint1
我很确定答案是否定的,因为 S 可能有不止一名成员。但是,如果我们将自己限制在 S 仅有一个成员的情况下,我是否可以合法地将 S 数组视为 int 数组?
不,类的布局根本没有影响,除了对于非标准布局类,它reinterpret_cast本身不会按预期工作,甚至在索引0或任何指针算术(包括+0)处访问都将是 UB,因为在这种情况reinterpret_cast下甚至不会产生指向该int对象的指针。然后,您将尝试访问与(删除指针的)表达式类型不相似的类型的对象或对其进行指针算术。
目前还没有办法达到你想要的效果。
在 C++ 中,将指向标准布局类型 S 的指针重新解释为指向 S 的任何成员的指针是合法的,可能使用 offsetof 宏。
从技术上来说,目前除了第一个元素之外也是不可能的。但这是标准的缺陷。目前它没有正确指定reinterpret_cast<unsigned char*>应该生成一个指向对象表示的指针(这是唯一offset可以使用的方法)。本规范的细节对于哪些offsetof结构具有 UB 和哪些没有 UB 很重要。这并不简单。
所有这些都是基于标准保证(C++17 或更高版本)。这是否会在实践中给编译器带来问题是另一个问题。在实践中(我认为),只要确保满足所有对齐要求并且大小匹配,您可能就可以很好地使用当前的编译器。请注意,班级中只有一名成员并不能保证后者。最后可能仍然有填充。