我正在尝试编写一个可重用的消息对象,该对象将使用其属性,将它们转换为定界字符串(使用0x1d
组分隔符),将其放入char
缓冲区中,并且还可以进行反向操作(从char
回到对象)。
之所以必须这样做,是因为我完全受操作系统功能的限制,只能发送类型为char
和固定大小的消息,因此这是我的包装。
这是我到目前为止所拥有的。易于包装..现在,我该如何写一个明智的包装方法。如果这个班的每个孩子都必须手动解压缩这些数据,我可以,但是我不知道如何。我尝试过getline
,但随后我得到一个字符串,将不得不编写许多转换函数。必须有一种更简单的方法。
注意我在C ++ 98中。
#include <iostream>
#include <sstream>
#include <string.h>
class Msg {
public:
Msg(){
delim = 0x1d;
}
int8_t ia;
int16_t ib;
int32_t ic;
int64_t id;
uint8_t ua;
uint16_t ub;
uint32_t uc;
uint64_t ud;
std::string str = "aaa bbb ccc dddd";
char sz[64];
char delim;
// convert to a char buffer
void ToBuffer(unsigned char* b, int s){
std::stringstream ss;
ss << ia << delim
<< ib << delim
<< ic << delim
<< id << delim
<< ua << delim
<< ub << delim
<< uc << delim
<< ud << delim
<< str << delim
<< sz << delim;
strncpy((char*)b, ss.str().c_str(), s);
b[s-1] = '\0';
}
// convert from a char buffer
void FromBuffer(unsigned char* b, int s){
// what on earth to do here..
// could use getline which returns a string after
// each delimiter, then convert each string to the
// value in a known order.. but at that point I may
// as well have written this all in C... !
}
void Print(){
std::cout
<< " ia " << ia
<< " ib " << ib
<< " ic " << ic
<< " id " << id
<< " ua " << ua
<< " ub " << ub
<< " uc " << uc
<< " ud " << ud
<< " str " << str
<< " sz " << sz;
}
};
int main()
{
Msg msg;
msg.ia = 0xFE;
msg.ib = 0xFEFE;
msg.ic = 0xFEFEFEFE;
msg.id = 0xFEFEFEFEFEFEFEFE;
msg.ua = 0xEE;
msg.ub = 0xDEAD;
msg.uc = 0xDEADBEEF;
msg.ud = 0xDEADBEEFDEADBEEF;
snprintf(msg.sz, 64, "this is a test");
msg.Print();
int s = 128;
unsigned char b[s];
msg.ToBuffer(b, s);
Msg msg2;
msg2.FromBuffer(b, s);
//msg2.Print();
return 0;
}
好,所以它可以工作,但是将缓冲区放入字符串流中只是一个丑陋的事情,所以您可以使用带有分隔符的std :: getline提取位,然后使用另一个字符串流或std :: stoi和朋友进行转换正确类型的项目:
https://repl.it/repls/GainsboroInsecureEvents
void FromBuffer(unsigned char* b, int s){
std::string item;
std::stringstream ss((char *)b);
// You don't NEED to use std::stringstream to convert
// the item to the primitive types - you could use
// std::stoi, std::stol, std::stoll, etc but using a
// std::stringstream makes it so you don't need to
// know which primitive type the variable is
std::getline(ss,item,'\x1d'); std::stringstream(item) >> ia;
std::getline(ss,item,'\x1d'); std::stringstream(item) >> ib;
std::getline(ss,item,'\x1d'); std::stringstream(item) >> ic;
std::getline(ss,item,'\x1d'); std::stringstream(item) >> id;
std::getline(ss,item,'\x1d'); std::stringstream(item) >> ua;
std::getline(ss,item,'\x1d'); std::stringstream(item) >> ub;
std::getline(ss,item,'\x1d'); std::stringstream(item) >> uc;
std::getline(ss,item,'\x1d'); std::stringstream(item) >> ud;
// Until you get to here. Then >> stops on a space
// and all the sudden you can't use >> to get the data
std::getline(ss,str,'\x1d');
// And a C string is even worse because you need to
// respect the length of the buffer by using strncpy
std::getline(ss,item,'\x1d'); strncpy(sz,item.c_str(),64); sz[63] = '\0';
}
因此,我认为更好的方法是创建一个使用新定界符的新ctype构面,并在字符串流中注入新构面,就像在此处changing the delimiter for cin (c++)所做的那样
这样我们就可以直接提取哪个更好:
https://repl.it/repls/GraveDraftyAdministrators
void FromBuffer(unsigned char* b, int s){
struct delimiter : std::ctype<char> {
delimiter() : std::ctype<char>(get_table()) {}
static mask const* get_table()
{
static mask rc[table_size];
rc[0x1d] = std::ctype_base::space;
return &rc[0];
}
};
std::stringstream ss((char *)b);
ss.imbue(std::locale(ss.getloc(), new delimiter));
ss >> ia
>> ib
>> ic
>> id
>> ua
>> ub
>> uc
>> ud
>> str
>> sz;
}