【发布时间】:2021-07-04 09:51:55
【问题描述】:
可以使用std::memmove() 将内存“移动”到同一位置,以便能够使用不同类型对其进行别名处理吗?
例如:
#include <cstring>
#include <cstdint>
#include <iomanip>
#include <iostream>
struct Parts { std::uint16_t v[2u]; };
static_assert(sizeof(Parts) == sizeof(std::uint32_t), "");
static_assert(alignof(Parts) <= alignof(std::uint32_t), "");
int main() {
std::uint32_t u = 0xdeadbeef;
Parts * p = reinterpret_cast<Parts *>(std::memmove(&u, &u, sizeof(u)));
std::cout << std::hex << u << " ~> "
<< p->v[0] << ", " << p->v[1] << std::endl;
}
$ g++-10.2.0 -Wall -Wextra test.cpp -o test -O2 -ggdb -fsanitize=address,undefined -std=c++20 && ./test
deadbeef ~> beef, dead
这是一种安全的方法吗?有什么注意事项?这里可以用static_cast代替reinterpret_cast吗?
【问题讨论】:
-
您仍然没有合适的
Parts对象。通过内存表示创建普通对象的可移植方法是先使用Parts p;,然后使用memcpy到&p。memmove在这里无关紧要。 -
我很确定这是未定义的行为,不管有没有
memmove。代码访问生命周期从未开始的Parts对象。我看不出memmove是如何改变这一点的。 -
@IgorTandetnik 但是
struct Parts不是implicit-lifetime type 是created by memmove? -
代码示例中没有
struct Parts对象。有一个std::uint32_t。有一个struct Parts*,它指向一个不是struct Parts的对象。 -
FYI C++20 引入了
std::bit_cast作为一种安全、便捷的方式来执行此操作。 cppreference 页面有一个示例实现,如果您的编译器尚未提供它(由于 GCC 11 FWIW),您可以使用它。
标签: c++ undefined-behavior strict-aliasing memmove