添加一个字符串或字符数组到一个字节向量
我目前正在研究一个类来创建和读出通过网络发送的数据包,到目前为止我已经使用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_
由于您使用的标准::矢量你的缓冲区,你可能也让它保持跟踪写入位置本身,避免不得不手动调整它的大小。您也可以通过避免使用函数模板写的附加功能的多个重载:
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;
}
但是,我需要一个单独的函数来读取字符串,因为这些函数可以是可变长度的。 感谢您的代码,我现在就试试看。 – 2010-04-28 12:45:40
我刚试过,添加部分得到一个段错误,找出原因的时间... – 2010-04-28 12:48:40
我没有看到任何错误:/ – 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;
通常尝试避免受保护的属性(受保护的方法很好),因为它们会减少类的封装。
不会导致段错误,它印刷得很好,出于某种奇怪的原因。我现在已经转向使用Ferruccio提出的模板,并且工作得很好,剩下的就是字符串的读取功能。 – 2010-04-28 13:42:34
你的问题表明追加一个字符串或字符数组的问题,但我没有看到试图做到这一点的代码。 – 2010-04-28 12:21:29
我删除了添加字符串或字符数组的代码,并希望有人向我展示应该如何完成。否则,我可以在阅读和书写时列出5次尝试 – 2010-04-28 12:22:30
不要混合使用printf和cout。改为使用cout。 另外stdio.h和它的喜欢被弃用。例如,使用。 对于每个C头文件,只需在其之前键入c并除去.h –
2010-04-28 12:25:49