c++ 将标准布局对象数组转换为元素数组

ikfrs5lh  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(94)

在C++中,法律的是reinterpret_cast一个指向standard-layout typeS的指针指向S的任何成员,可能使用the offsetof macro。如果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);

这是否意味着我可以通过x0访问整个数组?索引x0大于0是否法律的?我很确定答案是否定的,因为S可能有多个成员。但是,如果我们将自己限制在S只有一个成员的情况下,我可以合法地将S数组视为int数组吗?

qzwqbdag

qzwqbdag1#

我可以合法地将指针转换为int *:
是的
这是否意味着我可以通过x0访问整个数组?将x0的索引设置为大于0是否法律的?
不可以。您可以通过x0+0进行构造、解引用和访问。你也可以构造x0+1,但它将是一个对象指针,不能被解引用。不能形成指向任何其他索引的指针。从强制转换接收到的int*指向一个不属于int数组的int对象。这样的情况被视为它们属于大小为1的数组,并且指针算法仅在该数组内部定义。
我很确定答案是否定的,因为S可能有不止一个成员。但是如果我们把自己限制在S只有一个成员的情况下,我可以合法地把S的数组当作int的数组吗?
不,类的布局没有任何影响,除了对于非标准布局类,reinterpret_cast本身将无法按预期工作,甚至在索引0或任何指针算术(包括+0)处访问都将是UB,因为在这种情况下,reinterpret_cast甚至不会导致指向int对象的指针。然后,您将尝试访问一个类型与(指针删除)表达式类型不相似的对象或对其执行指针算术。
目前没有办法实现你想要的。
在C中,可以法律的将指向标准布局类型S的指针重新解释_转换为指向S的任何成员的指针,可能使用offsetof宏。
这在技术上是不可能的,目前也超出了第一个要素。但这是标准中的一个缺陷。它目前没有正确地指定reinterpret_cast<unsigned char*>应该产生一个指向对象表示的指针(这是offset可以使用的唯一方式)。本规范的细节将取决于哪些offsetof结构具有UB,哪些没有。这并不简单。
所有这些都是标准保证(C
17或更高版本)。这是否会在实践中给编译器带来问题是另一个问题。在实践中(我认为),只要确保满足所有对齐要求并且大小匹配,您可能就可以使用当前的编译器。请注意,后者并不能通过类中只有一个成员来保证。最后可能还有填充物。

e0bqpujr

e0bqpujr2#

是的,因为通过x0访问数组元素的合法性取决于类型S的属性。如果S只有一个成员,如提供的代码所示,则通过x0访问数组元素是法律的。这是因为reinterpret_cast有效地将S的数组视为int的数组。
然而,正如你提到的,这种方法只在S只有一个成员时有效。

相关问题