在 C# 中序列化这些值以在C++中作为已知结构正确读取时遇到问题
Having trouble serializing these values in C# to be properly read in C++ as a known struct
我们得到了另一个组织的程序,该程序从多播源收集数据并整理和保存该数据。它需要一个格式如下的C++结构:
#define SP_PACKET_SIZE 200
#define NAME_SIZE 64
struct spPacketStruct
{
int Size;
char Name[SP_PACKET_SIZE][NAME_SIZE];
double Value[SP_PACKET_SIZE];
};
显然我不能在 C# 中使用此结构,因为结构不能具有预初始化的数组,因此我想创建单个位并序列化它们。 所以现在我在 C# 中有这个:
int SpPacketSize;
char[,] SpNames = new char[SP_PACKET_SIZE, NAME_SIZE];
double[] SpValues = new double[SP_PACKET_SIZE];
我以前的经验是使用二进制编写器...我不需要在 C# 中反序列化,我只需要将其放入C++程序。我的测试序列化代码如下:
System.IO.MemoryStream outputstream = new System.IO.MemoryStream();
BinaryFormatter serializer = new BinaryFormatter();
serializer.TypeFormat = System.Runtime.Serialization.Formatters.FormatterTypeStyle.TypesWhenNeeded;
serializer.Serialize(outputstream, SpPacketSize);
serializer.Serialize(outputstream, SpNames);
serializer.Serialize(outputstream, SpValues);
byte[] buffer = outputstream.GetBuffer();
udpclient.Send(buffer, buffer.Length, remoteep);
我得到一个二进制数据包,但长度不正确,因为它仍然包含类型格式。当我在 Wireshark 中查看此数据包时,我看到它的开头有一个 System.Int32 符号。 这使得数据包大于预期,因此无法在C++端正确反序列化。
我添加了 TypesWhenNeed TypeFormat,认为我可以最小化它,但它没有改变......我注意到没有选择不打字格式,除非我在某处错过了它。
有没有人有任何关于如何在没有额外信息的情况下正确序列化此数据的提示?
虽然您不能预先初始化结构字段,也不能直接将大小放在 2D 数组ByValue
MarshalAs 属性中,但您可以做一些解决方法。您可以定义两个结构,如下所示:
const short SP_PACKET_SIZE = 200;
const short NAME_SIZE = 64;
struct spPacketStruct
{
public int Size;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SP_PACKET_SIZE)]
private fixedString[] names;
public fixedString[] Names { get { return names ?? (names = new fixedString[SP_PACKET_SIZE]); } }
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SP_PACKET_SIZE)]
private double[] value;
public double[] Value { get { return value ?? (value = new double[SP_PACKET_SIZE]); } }
}
struct fixedString
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAME_SIZE)]
public string Name;
}
通过将其他结构设置为原始结构的成员,可以通过将原始结构中的SizeConst
设置为第一维并将其设置为新结构中的第二维来指定两个维度的长度。将字段设为私有并为它们创建属性只是为了方便起见,因此在创建结构时不必自己分配数组。
然后你可以像这样序列化/反序列化结构(来自这个答案的代码:https://stackoverflow.com/a/35717498/9748260):
public static byte[] GetBytes<T>(T str)
{
int size = Marshal.SizeOf(str);
byte[] arr = new byte[size];
GCHandle h = default;
try
{
h = GCHandle.Alloc(arr, GCHandleType.Pinned);
Marshal.StructureToPtr(str, h.AddrOfPinnedObject(), false);
}
finally
{
if (h.IsAllocated)
{
h.Free();
}
}
return arr;
}
public static T FromBytes<T>(byte[] arr) where T : struct
{
T str = default;
GCHandle h = default;
try
{
h = GCHandle.Alloc(arr, GCHandleType.Pinned);
str = Marshal.PtrToStructure<T>(h.AddrOfPinnedObject());
}
finally
{
if (h.IsAllocated)
{
h.Free();
}
}
return str;
}
最后一件事 当尝试序列化/反序列化这样的结构时,请注意结构对齐方式,因为它可能会弄乱结构大小
- C++将文本文件中的数据读取到结构数组中
- 将内部带有矢量的结构保存/读取到二进制文件中
- 从 XML 中读取未指定结构的每个数据成员
- 如何读取没有数组或结构的 3 列文件
- 将结构向量保存到文件中,并从C++文件中读取结构向量
- 嵌套结构,从由空行分隔的文件中读取数据
- C++,从文件读取到结构,然后读取到向量(结构被推入向量太多次,而不仅仅是一次)
- 从只读内存中读取结构
- 为什么不读取带有指针的结构?
- 如何读取文件并将该文件分类为不同类型的数据,这些数据都存储在结构中的特定数组中
- 从文本文件中读取并输入到数组结构中,然后显示读取的数据C++
- 将文本文件读取到数组结构中
- 如何读取/查询文件系统和文件结构
- 从包含 IP 标头片段的二进制文件中读取结构的最佳方法是什么
- 使用结构读取和写入二进制文件
- 使用文件和结构读取数据并输出数据
- 使用结构 c++ 读取压缩文件 Gzread
- 结构读取C++
- 在 c++ 中使用消息结构读取/填充数据缓冲区的正确方法是什么?
- 将包含字符串属性的结构读取/写入二进制文件