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

89 天前
 wisefree
"
struct demo
{
	uint32_t x;
    double y;
    int arr[3];
}
"

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

2130 次点击
所在节点    C++
29 条回复
star9029
89 天前
没理解问题。。是想要反序列化?目前 cpp 没有官方反射,序列化之类的操作都没有完美的方法实现
venicejack
89 天前
用 protobuf 处理,code gen 成你想要的代码,c++是编译型语言,一切类型都需要在编译时确定下来
iOCZS
89 天前
没什么意义,你又用不到它的静态特性,只考虑动态特性,那不就是一个多字段的值的集合么。
424778940
89 天前
考虑 protobuf 或者 json 库吧 但这些也都是要预定义结构的
动态定义的基本没有, 但如果熟悉内存操作也不是不能作死弄一套, 但还是要预定义一套规范/协议才行
Cu635
89 天前
输入的字符串就是结构体语法再加上个双引号?双引号的格式是全都是例子这样的么?
如果是的话,看看能不能采用读入字符串-->去掉双引号-->去掉双引号的字符串输出/保存成文件-->用保存的文件再进行后续操作的思路。当然,具体实现可能要考虑各种情况。
wisefree
89 天前
@star9029 我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
wisefree
89 天前
@iOCZS 我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
wisefree
89 天前
@Cu635 我想开发一个二进制数据解析软件,用户输入结构体定义的字符串和二进制文件,我就可以把二进制解析出文本
terryching
89 天前
看看 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
89 天前
@wisefree 那你就按语法解析出结构体名字,字段类型和字段名称,然后根据偏移量,从二进制中读取数据,然后再组装成文本
neocanable
89 天前
提供个思路,如果这个活要我干,我就把 lua 搞进去,如果不让把 lua 搞进去。我就用 json 了。
churchill
89 天前
不明来源的二进制文件,即使能动态定义结构体,比如内嵌一个 TinyC 之类的东西,可是还有内存对齐呢,还是走协议的路子吧
wisefree
89 天前
@churchill 假设二进制文件全部是 1 字节对齐的
iOCZS
89 天前
正常情况下,为了对齐,字段顺序是可能被调整的。我觉得用 JSON 可能更好
wisefree
89 天前
@iOCZS 确实是 json 更好一点
beyondstars
89 天前
我觉得你可能需要的是 C++ 模板元编程 (TMP), TMP 允许你做图灵完备的编译期计算。这本是是教程: https://www.amazon.com/C-Templates-Complete-Guide-2nd/dp/0321714121
ysc3839
89 天前
印象中 libffi 是可以运行时解析的,去搜了一下似乎不行。
继续搜索发现原来是 Python 的 cffi 库支持这么干,解析代码用的是 pycparser 这个项目。
所以要求不高的话可以考虑嵌入 Python 来实现,否则的话还是找找其他解析 C 代码的库吧。
beyondstars
89 天前
你可以参考这个思路哈: 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
89 天前
std::map
Inn0Vat10n
89 天前
jit

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1015079

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX