V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wisefree
V2EX  ›  C++

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

  •  
  •   wisefree · 77 天前 · 2065 次点击
    这是一个创建于 77 天前的主题,其中的信息可能已经有所发展或是发生改变。
    "
    struct demo
    {
    	uint32_t x;
        double y;
        int arr[3];
    }
    "
    

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

    第 1 条附言  ·  77 天前
    我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
    第 2 条附言  ·  77 天前
    假设二进制文件全部是 1 字节对齐的
    29 条回复    2024-03-20 11:29:03 +08:00
    star9029
        1
    star9029  
       77 天前   ❤️ 1
    没理解问题。。是想要反序列化?目前 cpp 没有官方反射,序列化之类的操作都没有完美的方法实现
    venicejack
        2
    venicejack  
       77 天前   ❤️ 1
    用 protobuf 处理,code gen 成你想要的代码,c++是编译型语言,一切类型都需要在编译时确定下来
    iOCZS
        3
    iOCZS  
       77 天前   ❤️ 1
    没什么意义,你又用不到它的静态特性,只考虑动态特性,那不就是一个多字段的值的集合么。
    424778940
        4
    424778940  
       77 天前   ❤️ 1
    考虑 protobuf 或者 json 库吧 但这些也都是要预定义结构的
    动态定义的基本没有, 但如果熟悉内存操作也不是不能作死弄一套, 但还是要预定义一套规范/协议才行
    Cu635
        5
    Cu635  
       77 天前   ❤️ 1
    输入的字符串就是结构体语法再加上个双引号?双引号的格式是全都是例子这样的么?
    如果是的话,看看能不能采用读入字符串-->去掉双引号-->去掉双引号的字符串输出/保存成文件-->用保存的文件再进行后续操作的思路。当然,具体实现可能要考虑各种情况。
    wisefree
        6
    wisefree  
    OP
       77 天前
    @star9029 我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
    wisefree
        7
    wisefree  
    OP
       77 天前
    @iOCZS 我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
    wisefree
        8
    wisefree  
    OP
       77 天前
    @Cu635 我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
    terryching
        9
    terryching  
       77 天前
    看看 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  
       77 天前   ❤️ 1
    @wisefree 那你就按语法解析出结构体名字,字段类型和字段名称,然后根据偏移量,从二进制中读取数据,然后再组装成文本
    neocanable
        11
    neocanable  
       77 天前   ❤️ 1
    提供个思路,如果这个活要我干,我就把 lua 搞进去,如果不让把 lua 搞进去。我就用 json 了。
    churchill
        12
    churchill  
       77 天前   ❤️ 1
    不明来源的二进制文件,即使能动态定义结构体,比如内嵌一个 TinyC 之类的东西,可是还有内存对齐呢,还是走协议的路子吧
    wisefree
        13
    wisefree  
    OP
       77 天前
    @churchill 假设二进制文件全部是 1 字节对齐的
    iOCZS
        14
    iOCZS  
       76 天前   ❤️ 1
    正常情况下,为了对齐,字段顺序是可能被调整的。我觉得用 JSON 可能更好
    wisefree
        15
    wisefree  
    OP
       76 天前
    @iOCZS 确实是 json 更好一点
    beyondstars
        16
    beyondstars  
       76 天前   ❤️ 1
    我觉得你可能需要的是 C++ 模板元编程 (TMP), TMP 允许你做图灵完备的编译期计算。这本是是教程: https://www.amazon.com/C-Templates-Complete-Guide-2nd/dp/0321714121
    ysc3839
        17
    ysc3839  
       76 天前 via Android   ❤️ 1
    印象中 libffi 是可以运行时解析的,去搜了一下似乎不行。
    继续搜索发现原来是 Python 的 cffi 库支持这么干,解析代码用的是 pycparser 这个项目。
    所以要求不高的话可以考虑嵌入 Python 来实现,否则的话还是找找其他解析 C 代码的库吧。
    beyondstars
        18
    beyondstars  
       76 天前   ❤️ 1
    你可以参考这个思路哈: 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  
       76 天前
    std::map
    Inn0Vat10n
        20
    Inn0Vat10n  
       76 天前
    jit
    GeruzoniAnsasu
        21
    GeruzoniAnsasu  
       76 天前   ❤️ 1
    bl4ckoooooH4t
        22
    bl4ckoooooH4t  
       76 天前   ❤️ 1
    不用自己开发,010 editor 的 template 已经有这个功能了
    yyang179
        23
    yyang179  
       76 天前   ❤️ 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  
       76 天前
    这不就是基于流的解析,参考 IM 中长链接协议的制定这种。
    sjkdsfkkfd
        25
    sjkdsfkkfd  
       76 天前 via Android   ❤️ 1
    ImHex 有一个 pattern language 就是干这个的,你可以参考一下 https://github.com/WerWolv/PatternLanguage/
    aloxaf
        26
    aloxaf  
       76 天前   ❤️ 1
    Kaitai Struct ?
    neocanable
        27
    neocanable  
       76 天前
    @wisefree 这样假设好实现,hard code 一堆,估计莫名的 bug 会一堆一堆,找的时候痛苦的要死
    yanqiyu
        28
    yanqiyu  
       75 天前 via Android
    感觉是 jit 的活
    tyzandhr
        29
    tyzandhr  
       36 天前 via Android
    黑魔法:根据编译器模拟结构体内存布局。手动对齐。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3272 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 14:14 · PVG 22:14 · LAX 07:14 · JFK 10:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.