C++ 将结构附加到向量<;uint8_t>;
我正在写一个消息通信库,需要读取一些数据到一个结构,然后将这个结构附加到一个向量,然后再次读取,再次附加 如果在C语言中,memcpy工作得很完美,但我想让所有代码都采用C++11代码风格 我尝试使用std::copy,但它需要一个开始和结束interator,那么我如何才能像C++ 将结构附加到向量<;uint8_t>;,c++,c++11,C++,C++11,我正在写一个消息通信库,需要读取一些数据到一个结构,然后将这个结构附加到一个向量,然后再次读取,再次附加 如果在C语言中,memcpy工作得很完美,但我想让所有代码都采用C++11代码风格 我尝试使用std::copy,但它需要一个开始和结束interator,那么我如何才能像std::copy(&a,&a+sizeof(a),back_inserter(buffer))那样准确地使用std::copy呢?您可以执行以下操作: struct MyStruct { int a; dou
std::copy(&a,&a+sizeof(a),back_inserter(buffer))那样准确地使用std::copy呢代码>?您可以执行以下操作:
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));
(或某种程度)。
< P>这里是一个干净的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}; }
模板
结构范围{
它是b,e;
它的begin()常量{return b;}
It end()常量{return e;}
std::size_t size()常量{return end()-begin();}
};
模板
range_t 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));
}
模板
范围\u t为\u字节(t*t){
静态断言(std::is_琐碎地_可复制::value,“如果不是琐碎地可复制,那就糟糕了”);
自动*ptr=重新解释铸件(t);
返回范围(ptr,ptr+sizeof(T));
}
模板
范围\u t为\u字节(t const*t){
静态断言(std::is_琐碎地_可复制::value,“如果不是琐碎地可复制,那就糟糕了”);
自动*ptr=重新解释铸件(t);
返回范围(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;
}
模板
无效推送字节(标准::向量和目标,T常量*数据){
自动字节=作为字节(数据);
insert(target.end(),bytes.begin(),bytes.end());
}
模板
bool弹出字节(std::vector和src,T*数据){
自动字节=作为字节(数据);
if(bytes.size()>src.size())返回false;
std::copy(src.end()-bytes.size(),src.end(),bytes.begin());
resize(src.size()-bytes.size());
返回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 << "failed\n";
return -1;
}
std::cout << d2.buff << "\n";
struct一些\u数据{
int x,y;
字符buff[1024];
};
std::向量字节;
一些_数据{1,2,“hello”};
推入字节(字节和数据);
一些数据;
如果(!弹出字节(字节,&d2)){
std::cout您可以使用向量插入成员函数
这比复制好,因为向量插入知道如何分配内存(您不需要使用丑陋的back\u插入器)
void追加(std::vector&v,const MyStruct&s){
v、 插入(v.end(),(unsigned char*)&s,((unsigned char*)&s)+sizeof s);
}
完整代码
注意到这是一个非常简单的代码,与YAKK的答案相比,但是我认为对于一些人来说,不使用模板来读取代码可能更容易。我也使用C型的转换,有些人认为不应该在C++中完成,但是我发现对于这个用例来说,解释太过于冗长了。在这里,我仍然使用memcpy,因为您所做的实际上是旧的hat C。出于安全原因,我会添加一个静态断言,以确保
静态断言(std::is_pod_v,“必须是普通的旧数据”)你必须把指针投向<代码> uTI8*T*<代码>,这样我就不确定它是什么。最好的选择是不要使用Struts作为中介。@ Alxand HeSuZAGH结构完全是POD。@ ReaviSeDeSK我建议在这里使用C风格的界面,C++安全。多字节值被转换为一致的字节顺序,并使用重新解释\u cast
,因为您所做的实际上只是为C代码添加了更强的保证。静态断言
确保如果您更改代码,您有编译时保证不会引入危险行为。这返回\u inserter
可以进行一些优化,更不用说它的速度有多慢了。此外,执行缓冲区插入(buffer.end(),ptr,ptr+sizeof(data))
在优化方面要好得多,因为insert
可以预先保留最后一个挑剔:因为(u)int8\u t
是整数类型,假设从指针读取不是UB是不安全的,尽管我不知道有任何实现不typedef char int8\u t
。总之,使用(无符号)char
或std::byte
取而代之。@MárioFeroldi如果我先使用vector.reserve获得固定大小的内存会怎么样?back_inserter还会变慢吗?@reavenisadesk测量它!我的直觉说它有用,但不依赖直觉。我编写了一个测试代码,如auto ptr=reinterpret_cast(a_ptr->data);vec.insert(vec.end()它的工作原理很好,但是当我在代码中使用它时,编译器会抛出错误:没有匹配的成员函数来调用“插入”。我查找标准的INSERT接口,没有找到这样的定义,这是一个标准的C++向量接口吗?指针是迭代器。因此它是过载(4)。在这个链接上:我的答案也有完整的代码,你们可以在这里找到可编译的例子
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 << "failed\n";
return -1;
}
std::cout << d2.buff << "\n";
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) );
}
void append(std::vector<unsigned char>& v, const MyStruct& s){
v.insert(v.end(), (unsigned char*) &s, ((unsigned char*)&s)+sizeof s);
}