我需要在类中创建一个编码器函数
bool encodeMsg(unsigned char* buffer, unsigned short& len);
这个类有一些固定长度的成员和一些可变长度的向量(不同结构)。我必须基于这些成员变量的某个序列来编码Byte流。
这是一个可销售的版本,
class test
{
public:
test();
~test();
bool encodeMsg(unsigned char* buffer);
bool decodeMsg(const unsigned char* buffer, unsigned short len);
private:
unsigned char a; // 0x12
unsigned char b; // 0x34
unsigned char c; // 0x56
}
当我编码时,我想要的是缓冲区中的0x123456。
问题,
我应该如何分配内存?由于在调用此函数之前未知
有没有一种映射类对象内存的方法,它基本上给出了我想要的。
我知道这是一个非常基本的问题,但我想知道做这件事的最佳和常规方法。
我应该如何分配内存?由于在调用此函数之前未知
给定您当前的代码,调用者应该分配内存:
unsigned char buffer[3];
unsigned short len = sizeof buffer;
my_test_object.encodeMsg(buffer, len);
有没有一种映射类对象内存的方法,它基本上给出了我想要的。
这很含糊。如果使用(可能是编译器特定的)#pragma
或属性来确保字符值占用内存中的3个连续字节,并且只要不向类中添加任何虚拟函数,就可以使用:实现encodeMsg()
memcpy(buffer, (unsigned char*)this + offsetof(test, a), 3);
但是,这有什么意义?充其量,我无法想象memcpy
会比写它的"好"方法更快:
buffer[0] = a;
buffer[1] = b;
buffer[2] = c;
如果你的意思更类似于:
test* p = reinterpret_cast<test*>(buffer);
*p = *this;
这将具有未定义的行为,并且可能向缓冲区写入多达sizeof(test)
个字节,很可能是4而不是3,这可能会导致一些客户端代码缓冲区溢出,删除已经设置的NUL终止符等。
退一步说,如果你必须问这类问题,你应该担心采用良好的编程实践——只有当你掌握了这类事情之后,你才应该担心什么是最佳的。为了养成良好的习惯,你可能想看看boost序列化库,并首先适应它。
如果可以更改encodeMsg()
函数的接口,则可以将字节流存储在向量中。
bool test::encodeMsg(std::vector<unsigned char>& buffer)
{
// if speed is important you can fill the buffer some other way
buffer.push_back(a);
buffer.push_back(b);
buffer.push_back(c);
return true;
}
如果encodeMsg()
不会失败(不需要返回bool),您可以在其中创建并返回向量,如下所示:
std::vector<unsigned char> test::encodeMsg()
{
std::vector<unisgned char> buffer;
// if speed is important you can fill the buffer some other way
buffer.push_back(a);
buffer.push_back(b);
buffer.push_back(c);
return buffer;
}
C++的方法是使用流。只需实现插入运算符<<
,就可以像这个一样进行编码
std::ostream& operator<<(std::ostream& os, const test& t)
{
os << t.a;
os << t.b;
os << t.c;
return os;
}
与用于解码的提取算子>>
相同
std::istream& operator>>(std::istream& is, test& t)
{
is >> t.a;
is >> t.b;
is >> t.c;
return is;
}
这将内存管理转移到流和调用方。如果需要对类型进行特殊编码,则从istream
和ostream
派生编解码器并使用它们。
当使用像这样的的stringstream
时,可以从流中检索内存和大小
test t;
std::ostringstream strm;
strm << t;
std::string result = strm.str();
auto size = result.length(); // size
auto array = result.data(); // the byte array
对于一般可复制std::is_trivially_copyable<test>::value == true
的类,编码和解码实际上是直接的(假设您已经为buffer
:分配了内存
bool encodeMsg(unsigned char* buffer, unsigned short& len) {
auto* ptr=reinterprete_cast<unsigned char*>(this);
len=sizeof(test);
memcpy(buffer, ptr, len);
return true;
}
bool decodeMsg(const unsigned char& buffer){
auto* ptr=reinterprete_cast<unsigned char*>(this);
memcpy(ptr, buffer, sizeof(test));
return true;
}
或更短的
bool encodeMsg(unsigned char* buffer, unsigned short& len) {
len=sizeof(test);
memcpy(buffer, (unsigned char*)this, len);
return true;
}
bool decodeMsg(const unsigned char& buffer){
memcpy((unsigned char*)this, buffer, sizeof(test));
return true;
}
最有可能的是,由于填充,您将复制4个字节而不是3个字节。
就直接将某个东西解释为字节数组而言,将指针从test*转换为unsignedchar*并通过它访问对象是合法的,但不是相反。所以你可以写的是:
unsigned char* buffer encodeMsg( unsigned short& len) {
len=sizeof(test);
return reinterprete_cast<unsigned char*>(this);
}
bool decodeMsg(const unsigned char& buffer){
auto* ptr=reinterprete_cast<unsigned char*>(this);
memcpy(ptr, buffer, sizeof(test));
return true;
}