C++ 如果通过解析字符串定义一个结构体 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wisefree
V2EX    C++

C++ 如果通过解析字符串定义一个结构体

  •  
  •   wisefree 2024-02-08 20:22:54 +08:00 3419 次点击
    这是一个创建于 612 天前的主题,其中的信息可能已经有所发展或是发生改变。
    " struct demo { uint32_t x; double y; int arr[3]; } " 

    请问大家,假设有这样的一个字符串,C++有没有现成的库,可以方便地把字符串转成结构体定义呢?

    第 1 条附言    2024-02-08 21:56:43 +08:00
    我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
    第 2 条附言    2024-02-08 22:12:35 +08:00
    假设二进制文件全部是 1 字节对齐的
    29 条回复    2024-03-20 11:29:03 +08:00
    star9029
        1
    star9029  
       2024-02-08 20:30:14 +08:00   1
    没理解问题。。是想要反序列化?目前 cpp 没有官方反射,序列化之类的操作都没有完美的方法实现
    venicejack
        2
    venicejack  
       2024-02-08 20:30:27 +08:00   1
    用 protobuf 处理,code gen 成你想要的代码,c++是编译型语言,一切类型都需要在编译时确定下来
    iOCZS
        3
    iOCZS  
       2024-02-08 20:39:10 +08:00   1
    没什么意义,你又用不到它的静态特性,只考虑动态特性,那不就是一个多字段的值的集合么。
    424778940
        4
    424778940  
       2024-02-08 21:40:31 +08:00   1
    考虑 protobuf 或者 json 库吧 但这些也都是要预定义结构的
    动态定义的基本没有, 但如果熟悉内存操作也不是不能作死弄一套, 但还是要预定义一套规范/协议才行
    Cu635
        5
    Cu635  
       2024-02-08 21:47:01 +08:00   1
    输入的字符串就是结构体语法再加上个双引号?双引号的格式是全都是例子这样的么?
    如果是的话,看看能不能采用读入字符串-->去掉双引号-->去掉双引号的字符串输出/保存成文件-->用保存的文件再进行后续操作的思路。当然,具体实现可能要考虑各种情况。
    wisefree
        6
    wisefree  
    OP
       2024-02-08 21:56:11 +08:00
    @star9029 我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
    wisefree
        7
    wisefree  
    OP
       2024-02-08 21:57:26 +08:00
    @iOCZS 我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
    wisefree
        8
    wisefree  
    OP
       2024-02-08 21:57:47 +08:00
    @Cu635 我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
    terryching
        9
    terryching  
       2024-02-08 22:02:38 +08:00
    看看 GPT4 给出的答案:
    运行时解析:使用已有的数据结构,如 std::map 或自定义的数据结构,来在运行时模拟结构体。基于解析得到的信息(字段名、类型、数组大小等),你可以动态地存储和访问数据。这种方法牺牲了类型安全和编译时优化,但提供了灵活性。
    ```c++
    #include <iostream>
    #include <map>
    #include <vector>
    #include <string>
    #include <typeinfo>
    #include <cstdint>

    class DynamicStruct {
    public:
    std::map<std::string, std::vector<uint8_t>> fields;

    void addInt(const std::string& name, int value) {
    auto data = reinterpret_cast<uint8_t*>(&value);
    fields[name] = std::vector<uint8_t>(data, data + sizeof(value));
    }

    void addDouble(const std::string& name, double value) {
    auto data = reinterpret_cast<uint8_t*>(&value);
    fields[name] = std::vector<uint8_t>(data, data + sizeof(value));
    }

    int getInt(const std::string& name) {
    if(fields.find(name) != fields.end()) {
    auto& data = fields[name];
    return *reinterpret_cast<const int*>(data.data());
    }
    return 0; // Or throw an exception
    }

    double getDouble(const std::string& name) {
    if(fields.find(name) != fields.end()) {
    auto& data = fields[name];
    return *reinterpret_cast<const double*>(data.data());
    }
    return 0.0; // Or throw an exception
    }

    // Similar methods can be added for other types and arrays
    };

    int main() {
    DynamicStruct myStruct;
    myStruct.addInt("x", 123);
    myStruct.addDouble("y", 456.789);
    // For arrays, you might add them element by element or as a block if you know the size

    std::cout << "x = " << myStruct.getInt("x") << std::endl;
    std::cout << "y = " << myStruct.getDouble("y") << std::endl;

    // Accessing array elements would require additional methods

    return 0;
    }
    ```
    iOCZS
        10
    iOCZS  
       2024-02-08 22:03:16 +08:00   1
    @wisefree 那你就按语法解析出结构体名字,字段类型和字段名称,然后根据偏移量,从二进制中读取数据,然后再组装成文本
    neocanable
        11
    neocanable  
       2024-02-08 22:09:26 +08:00   1
    提供个思路,如果这个活要我干,我就把 lua 搞进去,如果不让把 lua 搞进去。我就用 json 了。
    churchill
        12
    churchill  
       2024-02-08 22:11:33 +08:00   1
    不明来源的二进制文件,即使能动态定义结构体,比如内嵌一个 TinyC 之类的东西,可是还有内存对齐呢,还是走协议的路子吧
    wisefree
        13
    wisefree  
    OP
       2024-02-08 22:12:54 +08:00
    @churchill 假设二进制文件全部是 1 字节对齐的
    iOCZS
        14
    iOCZS  
       2024-02-08 22:14:53 +08:00   1
    正常情况下,为了对齐,字段顺序是可能被调整的。我觉得用 JSON 可能更好
    wisefree
        15
    wisefree  
    OP
       2024-02-08 22:18:32 +08:00
    @iOCZS 确实是 json 更好一点
    beyondstars
        16
    beyondstars  
       2024-02-08 22:34:25 +08:00   1
    我觉得你可能需要的是 C++ 模板元编程 (TMP), TMP 允许你做图灵完备的编译期计算。这本是是教程: https://www.amazon.com/C-Templates-Complete-Guide-2nd/dp/0321714121
    ysc3839
        17
    ysc3839  
       2024-02-08 22:34:50 +08:00 via Android   1
    印象中 libffi 是可以运行时解析的,去搜了一下似乎不行。
    继续搜索发现原来是 Python 的 cffi 库支持这么干,解析代码用的是 pycparser 这个项目。
    所以要求不高的话可以考虑嵌入 Python 来实现,否则的话还是找找其他解析 C 代码的库吧。
    beyondstars
        18
    beyondstars  
       2024-02-08 22:57:41 +08:00  
    你可以参考这个思路哈: https://studiofuga.com/2016/03/07/a-compact-csv-parser-using-c-tmp/

    这个作者实现了一个编译期的 csv parser, 你也可以做一个编译期的 tokenizer, 然后做 parser, 然后做 synthesizer 只不过 target 就是 类型对象, 最终的效果可能类似于 `my_compiletime_parser<"{ int x; }">::type x;` 等价于 `struct {int x; } x;`.
    realJamespond
        19
    realJamespond  
       2024-02-08 23:35:17 +08:00
    std::map
    Inn0Vat10n
        20
    Inn0Vat10n  
       2024-02-09 00:11:02 +08:00
    jit
    GeruzoniAnsasu
        21
    GeruzoniAnsasu  
       2024-02-09 02:19:16 +08:00   1
    bl4ckoooooH4t
        22
    bl4ckoooooH4t  
       2024-02-09 09:52:06 +08:00   1
    不用自己开发,010 editor 的 template 已经有这个功能了
    yyang179
        23
    yyang179  
       2024-02-09 11:15:06 +08:00   1
    最近刚好做了个类似的功能,提供一个 C++能嵌入 python 的思路:
    1. 结构体转 Python ,依托于 ctypeslib2 (这个库通过 clang 的词法分析,将结构体转为 python 的 ctypes ),ctypeslib2 调用 clang 会有些问题,会需要改写 ctypeslib2 的部分源码。
    2. Python 可以通过转出的库,用 from_buffer_copy 函数直接做结构体与数据映射(前提是指针长度,对齐方式需要一致),然后导出想要的数据结构,这一步用 python 写起来比 C++方便很多很多。
    3. C++调用 python 的脚本,或者通过 pybind11 调用 python 的函数
    gaifanking
        24
    gaifanking  
       2024-02-09 13:10:12 +08:00
    这不就是基于流的解析,参考 IM 中长链接协议的制定这种。
    sjkdsfkkfd
        25
    sjkdsfkkfd  
       2024-02-09 13:44:20 +08:00 via Android   1
    ImHex 有一个 pattern language 就是干这个的,你可以参考一下 https://github.com/WerWolv/PatternLanguage/
    aloxaf
        26
    aloxaf  
       2024-02-09 15:14:59 +08:00   1
    Kaitai Struct ?
    neocanable
        27
    neocanable  
       2024-02-09 21:46:36 +08:00
    @wisefree 这样假设好实现,hard code 一堆,估计莫名的 bug 会一堆一堆,找的时候痛苦的要死
    yanqiyu
        28
    yanqiyu  
       2024-02-09 22:40:11 +08:00 via Android
    感觉是 jit 的活
    tyzandhr
        29
    tyzandhr  
       2024-03-20 11:29:03 +08:00 via Android
    黑魔法:根据编译器模拟结构体内存布局。手动对齐。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5417 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 01:22 PVG 09:22 LAX 18:22 JFK 21:22
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86