从字符串或字符串流中设置和获取数据
Setting and getting data from a string or stringstream
我正在尝试编写一个可重用的消息对象,该对象将采用其属性,将它们转换为定界字符串(使用 0x1d
组分隔符),将其放入 char
缓冲区中,然后也可以反向操作(从 char
回到对象)。
我必须这样做的原因是我完全受到 OS 功能的限制,只能发送 char
类型和固定大小的消息,所以这是我的包装器那。
这是我目前所拥有的。易于打包..现在,我该如何编写一种明智的方式来解压它。如果此 class 的每个子项都必须手动解压此数据,我可以接受,但我只是不知道如何解压。我试过 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] = '[=10=]';
}
// 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] = '[=10=]';
}
所以我认为更好的方法是创建一个使用新定界符的新 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;
}
我正在尝试编写一个可重用的消息对象,该对象将采用其属性,将它们转换为定界字符串(使用 0x1d
组分隔符),将其放入 char
缓冲区中,然后也可以反向操作(从 char
回到对象)。
我必须这样做的原因是我完全受到 OS 功能的限制,只能发送 char
类型和固定大小的消息,所以这是我的包装器那。
这是我目前所拥有的。易于打包..现在,我该如何编写一种明智的方式来解压它。如果此 class 的每个子项都必须手动解压此数据,我可以接受,但我只是不知道如何解压。我试过 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] = '[=10=]';
}
// 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] = '[=10=]';
}
所以我认为更好的方法是创建一个使用新定界符的新 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;
}