将结构追加到矢量<uint8_t>
Append structs to a vector<uint8_t>
我正在写一个消息com com comuntiction lib,需要将一些数据读取到struct,并将该结构附加到向量,然后再次阅读,再次附加。
如果用C语言,memcpy的工作原理是完美的,但是我想用C 11代码样式制作所有代码。
我尝试使用std ::复制,但是它需要一个开始和结束互机,那么我如何才能使用std :: copy(例如 std::copy(&a, &a + sizeof(A), back_inserter(buffer));
?
您可以做到这一点:
struct MyStruct {
int a;
double b;
int c;
};
std::vector<uint8_t> buffer;
MyStruct data { 42, 3.14159, 123 };
uint8_t* ptr = reinterpret_cast<uint8_t*>(&data);
std::copy(ptr, ptr + sizeof(data), back_inserter(buffer));
请注意,在这种情况下,下方的std::copy
只需恢复到std::memcpy
,而reinterpret_cast
抛弃了该语言的所有类型安全性。亚历山大使用static_assert
的建议是一个很好的建议。
编辑:
mário是对的,back_inserter
会导致std::copy
不等于std::memcpy
。一种替代方法可能是首先重新分配您的缓冲区,然后复制:
size_t len = buffer.size();
buffer.resize(len+sizeof(data));
std::copy(ptr, ptr + sizeof(data), buffer.data() + len);
(或某种程度上的东西)。
这是一种干净的C 做到的方法:
首先是简单的范围类型:
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
std::size_t size() const { return end()-begin(); }
};
template<class It>
range_t<It> range(It s, It f) { return {s,f}; }
它代表了一些迭代器。
接下来,一些将POD数据视为字节的功能:
template<class T>
range_t< unsigned char* > as_bytes( T* t ) {
static_assert( std::is_trivially_copyable<T>::value, "bad idea if not trivially copyable" );
auto* ptr = reinterpret_cast<unsigned char*>(t);
return range(ptr, ptr+sizeof(T));
}
template<class T>
range_t< unsigned char const* > as_bytes( T const* t ) {
static_assert( std::is_trivially_copyable<T>::value, "bad idea if not trivially copyable" );
auto* ptr = reinterpret_cast<unsigned char const*>(t);
return range(ptr, ptr+sizeof(T));
}
既读写版本。
接下来,将结构并塞入向量的功能或将其弹出:
:template<class T>
void push_bytes_in( std::vector<std::uint8_t>& target, T const* data ) {
auto bytes = as_bytes(data);
target.insert( target.end(), bytes.begin(), bytes.end() );
}
template<class T>
bool pop_bytes_out( std::vector<std::uint8_t>& src, T* data ) {
auto bytes = as_bytes(data);
if (bytes.size() > src.size()) return false;
std::copy( src.end()-bytes.size(), src.end(), bytes.begin() );
src.resize( src.size()-bytes.size() );
return true;
}
最后,测试代码:
struct some_data {
int x, y;
char buff[1024];
};
std::vector<std::uint8_t> bytes;
some_data data{1,2, "hello"};
push_bytes_in( bytes, &data );
some_data d2;
if (!pop_bytes_out( bytes, &d2)) {
std::cout << "failedn";
return -1;
}
std::cout << d2.buff << "n";
现场示例。
,如果它们的速度太慢,无法预先大小缓冲区,然后使用std副本或memcpy推出字节,我们可以优化推送字节。但是,您应该谨慎地确保在这种情况下保留指数数据。
template<class T>
void push_bytes_in( std::vector<std::uint8_t>& target, T const* data ) {
if (target.capacity() < target.size()+sizeof(T)) {
target.reserve( target.capacity()*3/2 +1 );
}
auto bytes = as_bytes(data);
target.resize( target.size() + sizeof(T) );
std::copy( bytes.begin(), bytes.end(), target.end()-sizeof(T) );
}
可能会更快一些。
您可以使用向量插入成员函数。
这比复制要好,因为向量插入知道如何分配内存(您不需要使用丑陋的back_inserter)。
void append(std::vector<unsigned char>& v, const MyStruct& s){
v.insert(v.end(), (unsigned char*) &s, ((unsigned char*)&s)+sizeof s);
}
此处的完整代码
请注意,与Yakk答案相比,这是非常简单的代码,但我认为某些人在没有模板的情况下读取代码可能会更容易。另外,我使用的是某些人认为不应该在C 中完成的C样式,但我发现重新解释了该用例的冗长。
- EASTL矢量<向量<int>>连续的
- 从值小于256的uint16到uint8的Endian安全转换
- 你能把一个向量<int64>投射到一个向量<uint8>吗
- SSCANF 进入 uint8 阵列失败
- 着色器将uint8投射到float,并将其重新解释回uint
- 将指针uint8覆盖到指针uint16
- 创建一个包含30亿个uint8元素的向量
- 将 Uint8(浮点AUDIO_F32)转换为int16_t(16 位 PCM)
- UINT8/16 /32/etc 和 INT8/16/32/etc 在 libtiff 中不起作用?
- 错误:无法将'uint8* {aka unsigned int*}'转换为"常量emxArray_uint8_T*"?
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 将具有不同字段的结构转换为 uint8 的数组
- uint32, int16, uint8 .为什么这些常用的数据类型没有进入标准
- C 字符串比较“祝您好运”&gt;“再见”
- 如何将 uint8 列表转换为其相应的有符号值
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- 兼容的声明 __attribute__ ((节( ".abc.dfe" ))) 常量易失性 uint8 属性变量 = 0;- 符合MISRA标准
- 如何将UINT8*施放到UINT32
- 如何将元素从 Swift 中的 [UnsafeMutablePointer<UInt8>] 转换为 C++ 中的 UInt8 *
- 从字符串转换为 uint8,反之亦然