与 C# 中的数组缓冲区联合

Posted

技术标签:

【中文标题】与 C# 中的数组缓冲区联合【英文标题】:Union with array buffer in C# 【发布时间】:2019-03-14 21:30:15 【问题描述】:

我一直在研究一些定义了数据缓冲区的接口,它可以转换为c union中的相关数据结构,如下所示,

union DATA_STRUCTURE 
    uint8_t buffer[BUFFER_SIZE];
    A_STRUCT a;
    B_STRUCT b;
; 

我可以将接收到的数据放入buffer中,根据buffer中某处定义的数据类型使用a或b读取数据。

现在我要重写c#中的接口程序,在c#中找不到union like语法,发现有很多类似的帖子,建议使用FieldOffset作为下面,

  [StructLayout(LayoutKind.Explicit)]
  struct MyUnion
  
    [FieldOffset(0)] int I;
    [FieldOffset(0)] float F;
  

我只是尝试定义如下结构,

  [StructLayout(LayoutKind.Explicit, Size = 16)]
  struct MyUnion
  
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    [FieldOffset(0)] public byte[] buffer;
    [FieldOffset(0)] public A_STRUCT a;
    [FieldOffset(0)] public B_STRUCT b;
  
  MyUnion data;

但我无法通过 data.buffer[0] = x; 之类的语句将数据填充到缓冲区中。 它将显示错误“使用可能未分配的字段'缓冲区'”。 此外,即使我可以将值放入缓冲区,如果我尝试通过 a 或 b 访问数据,似乎也会返回相同的错误。

我也尝试过使用带有不安全选项的指针方法,但似乎我仍然无法获取不安全结构的地址,不允许以下语句,

  byte *ptr = (byte *) &data;
  byte *ptr = data.buffer;
  byte *ptr = &data.buffer[0];

也许我仍然错过了使用不安全关键字的一些东西。

请问有没有办法在 C# 中针对上述情况实现联合结构?

非常感谢。

【问题讨论】:

【参考方案1】:

由于数组是一个托管对象(不是结构),我认为你不能真正用它来玩联合风格的把戏。

我只会使用普通的byte[] 直到我准备好转换,然后从数组中获取IntPtr(可能通过fixed),然后使用Marshal.PtrToStructure 获取@987654327 @ 或 B_STRUCT。当然,如果您的访问模式更像:

将其视为数组 将其视为A_STRUCT 将其视为数组 将其视为B_STRUCT

【讨论】:

感谢您的建议。通过将 IntPtr 与 Marshal.PtrToStructure 一起使用,可以帮助使用该结构从缓冲区中检索数据。但是,PtrToStructure 将创建数据的副本,而不是指向原始内存位置。由于原始缓冲区将用于返回,因此需要将数据转换回缓冲区。它需要通过 Marshal.StructureToPtr 将内容复制到 IntPtr,然后使用 Marshal.Copy 将内容填充回缓冲区。通过使用一些元帅操作,我可以得到与以前相似的结果。非常感谢。

以上是关于与 C# 中的数组缓冲区联合的主要内容,如果未能解决你的问题,请参考以下文章

将字符串数组作为缓冲区传递给 C++ 到 C#

如何将 UI 与 C# 中的渲染分开?

无法将固定大小的字节数组从结构复制到 C# 结构中的另一个数组

协议缓冲区,让 C# 与 C++ 对话:类型问题和架构问题

(15) C# 抽取SuperSocket库里的缓冲区类

我可以设置 openGL 缓冲区以按照与 OBJ 文件类似的原理工作吗?