我有一个 C# 应用程序,需要与 Python 共享一些二进制数据,并且我计划使用共享内存(内存映射文件)。因此,我需要两边都有相同的二进制结构。
我在 C# 中创建了一个结构体 (
ST_Layer
),其中包含另一个结构体 (ST_Point
) 的项目数组。为了访问这些项目,我定义了一个函数 getPoint
,它将返回指向所请求的位置的指针 ST_Point
。
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
class TestProgram
{
[StructLayout(LayoutKind.Explicit, Pack = 8)]
public struct ST_Point
{
[FieldOffset(0)] public double X;
[FieldOffset(8)] public double Y;
}
[StructLayout(LayoutKind.Explicit, Pack = 8)]
public unsafe struct ST_Layer
{
[FieldOffset(0)] public ushort nPoints;
[FieldOffset(8)] public double fHeight;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
[FieldOffset(16)] public ST_Point[] Points;
public unsafe ST_Point* getPoint(int n)
{
fixed (ST_Layer* thisPtr = &this)
{
int ptr = (int)&(thisPtr->Points) + n * ((16 + 3) / 4) * 4; // Sizeof ST_Point 16
return (ST_Point*)ptr;
}
}
}
static void Main(string[] args)
{
unsafe
{
ST_Layer layer = new ST_Layer();
layer.nPoints = 3;
layer.fHeight = 4;
layer.getPoint(0)->X = 5;
layer.getPoint(3)->Y = 6;
for (int i = 0; i < 10; i++)
Debug.WriteLine("Data [" + i + "] " + layer.getPoint(i)->X + ", " + layer.getPoint(i)->Y + " - ");
while (true)
Thread.Sleep(50);
}
}
}
我有两个问题:
getPoint
函数来访问 ST_Point
数组,因为我还没有看到更好的访问它的方法。是否可以将其作为普通数组访问(即layer.Points[0].X
)?我无法创建 ST_Point
(layer.Points = new ST_Point[10]
) 数组,因为它将在 ST_Layer
之外创建,并且数据不会传递给 Python。ST_Point
的各个字段。
谢谢您的帮助。
[另外,感谢 R. Martinho Fernandes 对于 x86/x64 问题的提示]
如果您使用的是最新版本的 .NET,您可以使用
System.Runtime.CompilerServices.InlineArray
直接从 MMF 读取和写入结构,无需任何不安全代码:
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
namespace Console1;
public static class Program
{
static void Main()
{
using MemoryMappedFile mmf = MemoryMappedFile.CreateNew("MappedFile", 1000);
var view = mmf.CreateViewAccessor();
using UnmanagedMemoryAccessor accessor = view;
var s = new ST_Layer();
for (int i = 0; i < 10; ++i)
{
s.Points[i] = new ST_Point { X = i, Y = -i };
}
long offset = 500; // Arbitrary offset with the MMF.
view.Write(offset, ref s);
view.Read(offset, out ST_Layer t);
for (int i = 0; i < 10; ++i)
{
Console.WriteLine($"{s.Points[i].X}, {s.Points[i].Y}");
}
}
}
[StructLayout(LayoutKind.Explicit, Pack = 8)]
public struct ST_Point
{
[FieldOffset(0)] public double X;
[FieldOffset(8)] public double Y;
}
[System.Runtime.CompilerServices.InlineArray(10)]
public struct TenPoints
{
ST_Point _firstElement;
}
[StructLayout(LayoutKind.Explicit, Pack = 8)]
public struct ST_Layer
{
[FieldOffset(0)] public ushort nPoints;
[FieldOffset(8)] public double fHeight;
[FieldOffset(16)] public TenPoints Points;
}