【问题标题】:Can an array of a union type be cast to a pointer of the active type?联合类型的数组可以转换为活动类型的指针吗?
【发布时间】:2017-10-05 06:40:49
【问题描述】:

给定一个union类型的数组,如果满足以下条件:

  • 数组中每个union的活动成员都是一样的,
  • sizeofunion中的每个成员都是一样的,并且
  • alignofunion中的每个成员都是一样的
  • (可能)联合满足StandardLayoutType 的要求

那么以下操作是否安全:

  1. 将此数组转换为活动类型的指针(目的是将其作为活动类型的数组寻址)
  2. 解决上述数组的第一个元素以外的任何内容?
  3. 假设 1 和 2 是可能的;这适用于非标准布局类型吗?

例如,考虑以下代码段:

template<typename T, typename U>
union storage_type
{
    T value0;
    U value1;
};

static_assert( sizeof(int) == sizeof(float), "" );
static_assert( alignof(int) == alignof(float), "" );

storage_type<int,float> storage[] = { {1}, {2}, {3} };

// the active type of all storage_type is 'int', so cast to int*
// to be treated as an array of ints

auto* array = reinterpret_cast<int*>(&storage[0]);

assert( array[0] == 1 );
assert( array[1] == 2 );
assert( array[2] == 3 );

我对 C++ 标准对这种情况的明确规定很感兴趣。我知道StandardLayoutTypes 可以安全地转换为结构的第一个成员或联合的活动元素,所以我怀疑我的第一个转换是安全的;但我不确定这是否适用于数组,并将其视为活动类型的数组。

我尝试在 SO 和 C++ 标准(N4660 C++17 草案)上进行一些搜索——但我没有任何运气

注意:由于编译器具有 C 兼容性,这个问题不是关于这是否会在实践中工作;这是一个严格的问题,它是否调用 C++ 中的 UB,以及它是否违反严格的别名规则。

【问题讨论】:

    标签: c++ arrays pointers unions


    【解决方案1】:

    理论上,这可能会失败。按照标准:

    联合的大小足以包含其最大的数据成员。

    因此,理论上,sizeof(my_union) 和 sizeof(largest_member) 可能不同。

    如果你的 static_assert() 是一样的,那么:

    int* array = &storage[0].value0;
    

    ... 这样做了,由于数组索引的工作原理,您无需 UB。

    【讨论】:

    • union 大小的 12.3\1 引用很好。虽然我不相信它不是是UB。实际上,由于这句话,我更加确信它充其量是 实现定义的 行为,因为寻址是否有效将由编译器和平台决定。只有第一次强制转换为指针(我的问题中的 1.)才是有效且合法的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-28
    • 2016-05-07
    • 2021-09-20
    相关资源
    最近更新 更多