将字节有效地转换为C#中的结构数组

huangapple go评论61阅读模式
英文:

Effectively convert bytes to array of structures in C#

问题

以下是翻译好的部分:

My C# application interacts with the C application via the "callbacks" mechanism.

On the C side I have Point struct:

struct Point {
  float x, y, z;
};

To transfer points from C to C# I pass my C# delegate callback function pointsCallback to C function getPoints.

typedef void(*PointsCallback)(const Point* points, int size);

void getPoints(PointsCallback callback);
delegate void PointsCallback(IntPtr points, int size);

[DllImport(...)]
static extern void getPoints(PointsCallback callback);

My PointsCallback C# implementation looks like this:

[StructLayout(LayoutKind.Sequential)]
struct Point {
  public float x, y, z;
}

// called from c code
void PointsCallbackImpl(IntPtr points, int size) {
  var pointSize = Marshal.SizeOf<Point>();
  var myPoints = new List<Point>();
  for (int i = 0; i < size; ++i) {
    myPoints.Add(Marshal.PtrToStructure<Point>(points + i * pointSize));
  }
  // do something with myPoints
}

The problem is this code is quite slow compared to python's np.array which allows me to save all points as a binary array and interpret them via np.dtype.

Is there any C# analog to np.array behavior, which allows to store everything in binary form and only interpret data as some structs?

英文:

My C# application interacts with the C application via the "callbacks" mechanism.

On the C side I have Point struct:

struct Point {
  float x, y, z;
};

To transfer points from C to C# I pass my C# delegate callback function pointsCallback to C function getPoints.

typedef void(*PointsCallback)(const Point* points, int size);

void getPoints(PointsCallback callback);
delegate void PointsCallback(IntPtr points, int size);

[DllImport(...)]
static extern void getPoints(PointsCallback callback);

My PointsCallback C# implementation looks like this:

[StructLayout(LayoutKind.Sequential)]
struct Point {
  public float x, y, z;
}

// called from c code
void PointsCallbackImpl(IntPtr points, int size) {
  var pointSize = Marshal.SizeOf&lt;Point&gt;();
  var myPoints = new List&lt;Point&gt;();
  for (int i = 0; i &lt; size; ++i) {
    myPoints.Add(Marshal.PtrToStructure&lt;Point&gt;(points + i * pointSize));
  }
  // do something with myPoints
}

The problem is this code is quite slow compared to python's np.array which allows me to save all points as a binary array and interpret them via np.dtype.

Is there any C# analog to np.array behavior, which allows to store everything in binary form and only interpret data as some structs?

答案1

得分: 3

你可以使用 System.Memory<T> 类型来与包含二进制数据表示的内存块进行交互。它允许将数据解释为某个结构体。

示例:

struct Example
{
    public int IntValue;
    public float FloatValue;
}

byte[] dataBytes = new byte[] { 0x01, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00 };

Memory<byte> dataMemory = new Memory<byte>(dataBytes);

// 将内存强制转换为 Memory<Example> 对象
Memory<Example> dataMemory = MemoryMarshal.Cast<byte, Example>(dataMemory);

Example data = dataMemory.Span[0];

int intValue = data.IntValue; // intValue == 1
float floatValue = data.FloatValue; // floatValue == 1.0f
英文:

You can use System.Memory&lt;T&gt; type to interact with a block of memory containing a binary data representation. It allows interpreting the data as some struct.

Example:

struct Example
{
    public int IntValue;
    public float FloatValue;
}

byte[] dataBytes = new byte[] { 0x01, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00 };

Memory&lt;byte&gt; dataMemory = new Memory&lt;byte&gt;(dataBytes);

// Cast the memory to a Memory&lt;Example&gt; object
Memory&lt;MyData&gt; dataMemory = MemoryMarshal.Cast&lt;byte, Example&gt;(dataMemory);

MyData data = dataMemory.Span[0];

int intValue = data.IntValue; // intValue == 1
float floatValue = data.FloatValue; // floatValue == 1.0f

答案2

得分: 3

以下是您要翻译的部分:

"不确定这个上下文中的 'slow' 是什么意思,但下面的示例需要0.3285毫秒,或328500纳秒来转换1000个点。"

"并且这是我的测试:"

英文:

I am not sure what 'slow' means in this context, but the example below takes 0.3285 milliseconds, or 328500 nanoseconds to convert 1000 points.

[DllImport(&quot;msvcrt.dll&quot;, CallingConvention = CallingConvention.Cdecl)]
static unsafe extern void memcpy(void* dst, void* src, int count);

[StructLayout(LayoutKind.Sequential)]
struct Point
{
	public float x, y, z;
}

static unsafe void PointCallback(IntPtr ptPoints, int size)
{	
	Point[] points = new Point[size];
	fixed (void* pDest = &amp;points[0])             {
		memcpy(pDest, (void*)ptPoints, Marshal.SizeOf&lt;Point&gt;() * size);
	}
}

And here is my test:

Point[] points = new Point[1000];
for (int i=0; i&lt;1000; i++) {
	points[i] = new Point() { x= i, y = i,z = i };
}

var ptPoints = GCHandle.Alloc(points, GCHandleType.Pinned);
PointCallback(ptPoints.AddrOfPinnedObject(), 1000);
ptPoints.Free();

huangapple
  • 本文由 发表于 2023年2月14日 21:41:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75448702.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定