从字符串或字符串流中设置和获取数据

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