[英]Manipulating byte vector through float pointer
是否可以通过其数据指针操作std::vector<unsigned char>
,就好像它是float
的容器一样?
这是一个根据需要编译和(看似?)运行的示例(GCC 4.8,C++11):
#include <iostream>
#include <vector>
int main()
{
std::vector<unsigned char> bytes(2 * sizeof(float));
auto ptr = reinterpret_cast<float *>(bytes.data());
ptr[0] = 1.1;
ptr[1] = 1.2;
std::cout << ptr[0] << ", " << ptr[1] << std::endl;
return 0;
}
这个片段成功地从字节缓冲区写入/读取数据,就好像它是一个float
数组一样。 通过阅读有关 reinterpret_cast的信息,我担心这可能是未定义的行为。 我对理解类型别名细节的信心太小了,我无法确定。
代码片段是否如上所述未定义的行为? 如果是这样,是否有另一种方法来实现这种字节操作?
不,这是不允许的。
C++ 不仅仅是“字节负载”——编译器(以及更抽象的语言)被告知您有一个unsigned char
容器,而不是float
容器。 不存在float
,你不能假装他们存在。
您正在寻找的规则(称为严格别名)可以在[basic.lval]/8
下找到。
相反会起作用,因为允许(通过同一段中的特殊规则)通过unsigned char*
检查任何类型的字节。 但是在您的情况下,从以unsigned char
开始生命的事物中“获取” float
的最快安全和正确方法是将std::memcpy
或std::copy
这些字节复制到存在的实际float
中:
std::vector<unsigned char> bytes(2 * sizeof(float));
float f1, f2;
// Extracting values
std::memcpy(
reinterpret_cast<unsigned char*>(&f1),
bytes.data(),
sizeof(float)
);
std::memcpy(
reinterpret_cast<unsigned char*>(&f2),
bytes.data() + sizeof(float),
sizeof(float)
);
// Putting them back
f1 = 1.1;
f2 = 1.2;
std::memcpy(
bytes.data(),
reinterpret_cast<unsigned char*>(&f1),
sizeof(float)
);
std::memcpy(
bytes.data() + sizeof(float),
reinterpret_cast<unsigned char*>(&f2),
sizeof(float)
);
只要这些字节在您的系统上形成有效的float
表示,就可以了。 当然,它看起来有点笨拙,但是一个快速的包装器 function 将很快完成它。
假设您只关心float
并且不需要可调整大小的缓冲区,一个常见的替代方法是生成一些std::aligned_storage
然后在结果缓冲区中进行一堆新的放置。 由于 C++17,您可以选择使用std::launder
,尽管在这种情况下调整向量的大小(阅读:重新分配其缓冲区)也是不可取的。
此外,这些方法非常复杂,并且会导致并非所有读者都能理解的复杂代码。 如果您可以清洗您的数据,使其“是”一系列float
,那么您不妨首先让自己成为一个不错的std::vector<float>
。 根据上述内容,如果您愿意,可以在该缓冲区中获取和使用unsigned char*
。
应该注意的是,在野外有很多代码使用您的原始方法(特别是在具有准系统 C 遗产的旧项目中)。 在许多实现中,它似乎可以工作。 但一个常见的误解是它是有效的和/或安全的,如果你依赖它,你很容易指令“重新排序”(或其他优化)。
对于它的价值,如果您禁用严格别名(GCC 允许将此作为扩展,而 LLVM 甚至没有实现它),那么您可能可以摆脱原始代码。 小心点。
是否可以通过它的数据指针来操作一个 std::vector,就好像它是一个浮点容器一样?
不完全的。 你的例子确实有UB。
但是,您可以重用这些字节的存储来在那里创建浮点数。 例子:
float* ptr = std::launder(reinterpret_cast<float*>(bytes.data()));
std::uninitialized_fill_n(ptr, 2, 0.0f);
在此之后, unsigned char 对象的生命周期已经结束,那里有浮点数。 使用ptr
定义明确。
这对您是否有用是另一回事。 首先从更简单的设计开始:为什么不简单地使用std::vector<float>
?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.