函数,该函数动态构造字节数组并返回长度



我需要在类中创建一个编码器函数

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。

问题,

  1. 我应该如何分配内存?由于在调用此函数之前未知

  2. 有没有一种映射类对象内存的方法,它基本上给出了我想要的。

我知道这是一个非常基本的问题,但我想知道做这件事的最佳和常规方法。

我应该如何分配内存?由于在调用此函数之前未知

给定您当前的代码,调用者应该分配内存:

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;
}

这将内存管理转移到流和调用方。如果需要对类型进行特殊编码,则从istreamostream派生编解码器并使用它们。

当使用像这样的的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;
}

最新更新