我有一个 std::vector<uint8_t> buffer
;我想加载一个大于 uint8_t
的数据类型(在这个例子中 uint16_t target
,但可以是任何东西)。我知道这个对象的内容已经被复制到位置size_t ID
在 buffer
.
据我所知,可以复制 target
和:
uint16_t target = *((uint16_t*) &buffer[ID]);
它适用于 gcc version 9.3.0
在使用 C++17 的 Ubuntu 上。但它看起来肯定是无意的。那么这个使用安全吗?也就是说,只要我确定知道
ID+sizeof(target)
在缓冲区内,我可以确定这将在所有操作系统上编译和运行而不会崩溃吗?
最佳答案
不,不是。你不能“假装”一个 uint16_t
在它不存在的地方存在。
在某些情况下,这种类型的双关语是安全的。例如,您可以将所需类型的现有对象重新解释为字节序列(通过 char*
、 unsigned char*
或 std::byte*
),但反之则不然。 ( ref )
C++ 对“存在”什么对象非常挑剔,在使用对象之前,您必须遵循语言规则使对象正确存在。这不仅仅是字节。编译器的“优化”甚至可以在我们解决实际计算机上的对齐等低级问题之前破坏程序的预期行为。
为了确保安全,您需要将字节复制到新的 uint16_t
中。 :
uint16_t target = 0;
std::copy(
reinterpret_cast<const char*>(&buffer[ID]),
reinterpret_cast<const char*>(&buffer[ID]) + sizeof(uint16_t),
reinterpret_cast<char*>(&target)
);
……或更短的:uint16_t target = 0;
std::memcpy(&target, &buffer[ID], sizeof(uint16_t));
请注意,这里我们正在利用我上面描述的别名豁免来重新解释 uint16_t
作为字节序列,写入该序列。因此,这些版本是安全的,只要您复制的字节确实形成了
uint16_t
的有效表示。在您的系统上(这对于主流平台很容易保证)。
关于c++ - 这是通过指针从 uint8_t vector 加载对象的安全方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65508613/