将数据解析为结构
Parsing data into struct
我正在做一个项目,我需要通过TCP/IP协议与设备进行通信。该设备发送大量数据,我想以某种方式将其解析为某些对象/结构。
数据包示例(在 TCP 缓冲区 [] 中(:
[64] [1] [78] [244] [77] [189] [249] [149] hcurrent
[64] [1] [78] [247] [89] [95] [104] [85] htarget
[0] [0] [0] [0] [0] [0] [0] [0] qcurrent
[188] [220] [97] [3] [66] [62] [0] [0] kcurrent
[66] [0] [102] [103] [66] [99][153] [154] mcurrent
[253] [191] [246] [74] [170] [216] [242] [29] fmode
[102] [191] [246] [74] [178] [44] [92] [72] tmil
[137] mode
现在,此包框架标识为:
double hcurrent
double htarget
double qcurrent
float kcurrent
float mcurrent
float fmode
float tmil
unsigned char mode
我的想法是,我可以以某种方式将数据直接解析为与上述结构相同的结构。当然,有必要确定一些键值来确定它是哪种类型的数据。
如何做到这一点?
由于我正在为iOS设备编码,因此它必须是objective-C或C(++(。
EDIT(测试用于将数据报的每个部分复制到结构中的方法(:我尝试读取前 4 个字节[0] [0] [1] [5]
的小型 Java 实现:
byte[] read = new byte[4];
int length = 0;
while (length < read.length) {
len = iStream.read(read, len, read.length);
}
int ByteLength = (int)unsignedIntToLong(read);
ByteLength = ByteLength-5;
state = 1; // Continue and work with next data.
和位操作方法:
public long unsignedIntToLong(byte[] b)
{
long l = 0;
l |= b[0] & 0xFF;
l <<= 8;
l |= b[1] & 0xFF;
l <<= 8;
l |= b[2] & 0xFF;
l <<= 8;
l |= b[3] & 0xFF;
return l;
}
所以我获取我之前提到的前 4 个字节,它决定了特定的东西,最后找到了 465
的长度。我的计划是对接收到的数据的所有其他部分重复此过程。
您将遇到的最大问题是结构不会以完全连续的形式存储数据,它们会根据单词边界对齐数据
这意味着,如果缓冲区一开始不包含结构,则不能简单地定义一个结构,然后将 buffer[] 强制转换为该结构。 相反,您可能需要做的是声明一个结构,然后使用指针偏移量一次在一个字段中对缓冲区 [] 的每个部分进行 memcpy。
如果此方法过于繁琐,通常可以关闭结构对齐,以便结构可以表示完全打包的数据。 MSVC 允许使用 #pragma 包来执行此操作。 但是,此方法会减慢对结构的内存访问。
编辑:下面是一个示例,显示了如何使用模板函数从缓冲区读取任何类型的内容,然后将偏移量更新到该缓冲区中。 可以使用此方法将任意数量的类型安全地逐个解析为结构:
// We want to copy raw data to this structure
// but the short will cause it to be unaligned
struct _parsed_structure
{
int a;
int b;
short c;
int d;
} parsed_structure;
template<typename T>
void read_and_update_offset (int & offset, char * buffer, T & var)
{
T * pInt = (T*)(buffer + offset);
var = *pInt;
offset += sizeof(T);
};
int _tmain(int argc, _TCHAR* argv[])
{
// Here's a buffer which we know contains ints and shorts, we could just cast it to our structure
// but this will cause errors because the structure will not be aligned properly.
char buffer[] = { 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 4, 0, 0, 0 };
// Read the first int from the buffer into the structure
int offset = 0;
read_and_update_offset(offset, buffer, parsed_structure.a);
read_and_update_offset(offset, buffer, parsed_structure.b);
read_and_update_offset(offset, buffer, parsed_structure.c);
read_and_update_offset(offset, buffer, parsed_structure.d);
// Print the values
std::cout <<
parsed_structure.a << " " <<
parsed_structure.b << " " <<
parsed_structure.c << " " <<
parsed_structure.d << " " << std::endl;
// Look the size of our structure is different than the size of our buffer due to alignment
std::cout <<
"sizeof(buffer)" << "==" << sizeof(buffer) << " " <<
"sizeof(parsed_structure)" << "==" << sizeof(parsed_structure) << std::endl;
return 0;
}
方法是编写方法nextInt
、nextDouble
等,这些方法将从流中读取字节(以正确的"字节序"顺序(并返回指定类型的值,将指针或索引更新到数组中。 这比尝试内联转换更易于管理,并且可能非常有效。 (你可以使方法C++与Objective-C相比提高效率。
- 如何在C++中序列化结构数据
- 正在转换结构数据的字节序
- C++ - 使用结构数据类型将单词中的单个小写字符更改为大写,反之亦然
- 在结构数据类型中更改每个字符的 ASCII 值
- C++ - 检查结构数据类型中的单词是否为回文
- 如何将结构数据成员传递到函数中
- 在std::线程中使用已分配的结构数据
- 将结构数据存储在循环缓冲区中
- 通过指针算法访问结构数据成员
- 将结构数据类型传递给 C++ 中的命名管道
- CLI/C# 将 std::vector<> 结构数据传递给 C#
- 使用来自 C 的内存地址的 Julia 读取/写入结构数据
- CPP 在读取结构数据时无限循环错误?
- 为什么C++编译器不优化对结构数据成员的读取和写入,而不是不同的局部变量?
- 使用Hazelcast替换共享内存结构数据
- 带有结构数据的 Gmock
- 结构数据D = {0}和结构数据D = {}之间是否存在任何区别
- 有没有办法将数组行为作为静态结构数据成员?
- 使用函数操作结构数据类型的值
- 有关结构数据'getting'的性能