添加一个字符串或字符数组到一个字节向量

问题描述:

我目前正在研究一个类来创建和读出通过网络发送的数据包,到目前为止我已经使用16位和8位整数(很好的无符号,但仍然)。添加一个字符串或字符数组到一个字节向量

现在的问题是我已经尝试了很多方法来复制它,但不知何故_buffer得到了损坏,它segfaulted,或结果是错误的。

我会很感激,如果有人能给我一个工作的例子。

我现在的代码可以在下面看到。

感谢,Xeross

主要

#include <iostream> 
#include <stdio.h> 
#include "Packet.h" 

using namespace std; 

int main(int argc, char** argv) 
{ 
    cout << "#################################" << endl; 
    cout << "#  Internal Use Only  #" << endl; 
    cout << "#  Codename PACKETSTORM  #" << endl; 
    cout << "#################################" << endl; 
    cout << endl; 

    Packet packet = Packet(); 
    packet.SetOpcode(0x1f4d); 

    cout << "Current opcode is: " << packet.GetOpcode() << endl << endl; 

    packet.add(uint8_t(5)) 
      .add(uint16_t(4000)) 
      .add(uint8_t(5)); 

    for(uint8_t i=0; i<10;i++) 
     printf("Byte %u = %x\n", i, packet._buffer[i]); 

    printf("\nReading them out: \n1 = %u\n2 = %u\n3 = %u\n4 = %s", 
     packet.readUint8(), 
     packet.readUint16(), 
     packet.readUint8()); 

    return 0; 
} 

Packet.h

#ifndef _PACKET_H_ 
#define _PACKET_H_ 

#include <iostream> 
#include <vector> 

#include <stdio.h> 
#include <stdint.h> 
#include <string.h> 

using namespace std; 

class Packet 
{ 
    public: 
     Packet() : m_opcode(0), _buffer(0), _wpos(0), _rpos(0) {} 
     Packet(uint16_t opcode) : m_opcode(opcode), _buffer(0), _wpos(0), _rpos(0) {} 

     uint16_t GetOpcode() { return m_opcode; } 
     void SetOpcode(uint16_t opcode) { m_opcode = opcode; } 

     Packet& add(uint8_t value) 
     { 
      if(_buffer.size() < _wpos + 1) 
       _buffer.resize(_wpos + 1); 

      memcpy(&_buffer[_wpos], &value, 1); 
      _wpos += 1; 

      return *this; 
     } 
     Packet& add(uint16_t value) 
     { 
      if(_buffer.size() < _wpos + 2) 
       _buffer.resize(_wpos + 2); 

      memcpy(&_buffer[_wpos], &value, 2); 
      _wpos += 2; 

      return *this; 
     } 

     uint8_t readUint8() 
     { 
      uint8_t result = _buffer[_rpos]; 
      _rpos += sizeof(uint8_t); 
      return result; 
     } 
     uint16_t readUint16() 
     { 
      uint16_t result; 
      memcpy(&result, &_buffer[_rpos], sizeof(uint16_t)); 

      _rpos += sizeof(uint16_t); 
      return result; 

     } 

     uint16_t m_opcode; 
     std::vector<uint8_t> _buffer; 
    protected: 

     size_t _wpos; // Write position 
     size_t _rpos; // Read position 
}; 

#endif // _PACKET_H_ 
+1

你的问题表明追加一个字符串或字符数组的问题,但我没有看到试图做到这一点的代码。 – 2010-04-28 12:21:29

+0

我删除了添加字符串或字符数组的代码,并希望有人向我展示应该如何完成。否则,我可以在阅读和书写时列出5次尝试 – 2010-04-28 12:22:30

+2

不要混合使用printf和cout。改为使用cout。 另外stdio.h和它的喜欢被弃用。例如,使用。 对于每个C头文件,只需在其之前键入c并除去.h – 2010-04-28 12:25:49

由于您使用的标准::矢量你的缓冲区,你可能也让它保持跟踪写入位置本身,避免不得不手动调整它的大小。您也可以通过避免使用函数模板写的附加功能的多个重载:

template <class T> 
Packet& add(T value) { 
    std::copy((uint8_t*) &value, ((uint8_t*) &value) + sizeof(T), std::back_inserter(_buffer)); 
    return *this; 
} 

现在你可以写任何POD类型到您的缓冲区。

含蓄:

int i = 5; 
o.write(i); 

或显式:

o.write<int>(5); 

为了从缓冲区读取,您将需要保持一个读取位置的轨迹:

template <class T> 
T read() { 
    T result; 
    uint8_t *p = &_buffer[_rpos]; 
    std::copy(p, p + sizeof(T), (uint8_t*) &result); 
    _rpos += sizeof(T); 
    return result; 
} 

您需要显式传递一个类型参数来读取。即

int i = o.read<int>(); 

警告:我经常使用这种模式,但由于我打字这个从我的头顶,有可能是代码的一些错误。

编辑:我只是注意到,你想能够添加字符串或其他非POD类型到您的缓冲区。你可以做到这一点通过模板特:

template <> 
Packet& add(std::string s) { 
    add(string.length()); 
    for (size_t i = 0; i < string.length(); ++i) 
     add(string[i]); 
    return *this; 
} 

这告诉编译器:如果添加被称为一个字符串类型,使用此功能,而不是一般的add()函数。

和阅读的字符串:

template <> 
std::string read<>() { 
    size_t len = read<size_t>(); 
    std::string s; 
    while (len--) 
     s += read<char>(); 
    return s; 
} 
+0

但是,我需要一个单独的函数来读取字符串,因为这些函数可以是可变长度的。 感谢您的代码,我现在就试试看。 – 2010-04-28 12:45:40

+0

我刚试过,添加部分得到一个段错误,找出原因的时间... – 2010-04-28 12:48:40

+0

我没有看到任何错误:/ – 2010-04-28 12:49:34

你可以使用std::string内部缓冲区,并添加新的元素时使用append()

因此,添加字符串或const char *将是微不足道的。

添加/写入uint8可以通过将其转换为char,将uint16 - 写入长度为sizeof(uint16_t)的char *来完成。

void write_uint16(uint16_t val) 
{ 
    m_strBuffer.append((char*)(&var), sizeof(val)); 
} 

阅读UINT16:

uint16_t read_int16() 
{ 
    return (*(uint16_t*)(m_strBuffer.c_str() + m_nOffset)); 
} 

你似乎是试图打印10个字节移出缓冲区时,你只增加了四个,这样的话你要逃跑的矢量结束。这可能会导致您的seg故障。

此外,您的printf正尝试将字符打印为带有%x的无符号整数。您需要使用static_cast<unsigned>(packet._buffer[i])作为参数。

风格: Packet packet = Packet();可能会导致两个对象被构造。只需使用Packet packet;

通常尝试避免受保护的属性(受保护的方法很好),因为它们会减少类的封装。

+0

不会导致段错误,它印刷得很好,出于某种奇怪的原因。我现在已经转向使用Ferruccio提出的模板,并且工作得很好,剩下的就是字符串的读取功能。 – 2010-04-28 13:42:34