直接通过 memcpy() 或 std::bit_cast() 创建的工会的活跃成员?

Active member of a union created directly through memcpy() or std::bit_cast()?

提问人:user541686 提问时间:10/1/2023 最后编辑:timrauuser541686 更新时间:10/1/2023 访问量:94

问:

请考虑以下代码:

#include <stdint.h>
#include <string.h>
#include <bit>

union U
{
    uint64_t ull;
    int32_t i[2];
};

int main(int argc, char *argv[])
{
    uint64_t x = argc;
    U u;
    if (true)
        u = std::bit_cast<U>(x);
    else
        ::memcpy(&u, &x, sizeof(x));
    auto r = u.i[0];
    r += u.i[1];
    r += u.ull;
    return r;
}

我有 3 个问题:

  1. 哪个成员紧挨着行处于活动状态?uauto r = ...

  2. 哪些行具有未定义的行为(如果有),为什么?

  3. 翻转是否会改变上面的答案,如果是这样,如何/为什么?truefalse

C++ 语言-lawyer C++20 联合

评论

0赞 Tim Roberts 10/1/2023
我不认为“主动”概念在这里起作用。 将被定义为 ,因此应该触发“精度损失”警告。rint32_tr += s.ull
0赞 user541686 10/1/2023
@TimRoberts:是的,我不担心精度下降;我只是担心这里潜在的UB。
0赞 David C. Rankin 10/1/2023
好吧,我需要更多的咖啡,你用了一个,然后我的阅读障碍大脑说.所以不,没有填充问题,没有不确定的位/值,也没有UB。unionS sstruct
0赞 user541686 10/1/2023
@DavidC.Rankin:啊,我会把它改成更清楚的。U
0赞 David C. Rankin 10/1/2023
咯咯地笑——有趣的是,大脑是如何运作的(尤其是一个衰老、疲惫的大脑)。我读了,然后以某种方式说服自己这是一个结构。它总是回到人类的易犯错误:我对 std::bit_cast 的阅读说你是安全的。union:)

答:

2赞 user17732522 10/1/2023 #1

在自动 r = ...线?

default-initialized 没有任何活动成员。u

std::bit_cast隐式创建嵌套在返回对象中的对象。仅当 的隐式对象创建开始其中一个子对象的生存期时,成员才会处于活动状态。隐式对象创建被指定为仅在将提供程序执行提供定义行为时才执行此操作。std::bit_cast

但是,无论哪个子对象的成员,隐式对象创建都将启动生存期,或者具有读取非活动成员的未定义行为。r += u.i[1];r += u.ull;

因此,无论 OR 如何,程序都具有未定义的行为,并且没有 成员处于活动状态。u

哪些行具有未定义的行为(如果有),为什么?

单个行不能具有未定义的行为。整个程序要么具有未定义的行为(对于给定的输入),要么没有。

当所有行都存在时,程序具有未定义的行为,但删除那些访问或访问的行将赋予程序定义的行为,因为隐式对象的创建将使另一个成员处于活动状态。(假设联合的复制分配旨在使同一成员在目标中处于活动状态,而在源中处于活动状态。我似乎不清楚这方面的规范。例如,参见 https://github.com/cplusplus/draft/issues/5193 中的讨论u.ullu.istd::bit_cast)

从真到假会改变上面的答案吗,如果是这样,如何/为什么?

同样的问题仍然存在。 此外,还会通过相同的规则隐式创建嵌套在目标中的对象。memcpy


此外,根据所涉及类型的输入和实现定义的表示,无论上述情况如何,都可能导致未定义的行为,从而在有符号积分算术上溢出。r += u.i[1];

评论

0赞 user17732522 10/1/2023
@user541686 这是我的理解,是的,除了一般工会操作的一些不确定性,例如关于任务:github.com/cplusplus/draft/issues/5193