2012-03-26 9 views
2

Ich verwende Shared Memory für Interprozesskommunikation in einer unsicheren Klasse. Ein Teil des Speichers ist reserviert, um ein festes Array von int zu halten.unsafe C#: Wie kann ich ein int [] von einem Zeiger auf einen bereits vorhandenen Speicherort erstellen?

Grundsätzlich habe ich eine Methode, die den gemeinsamen Speicher einrichtet. Etwas wie folgt aus:

private int* sizePtr; 

private ???* arrayPtr; 

void SetupMemory(byte *pointerToSharedMem) 

{ 

    this.sizePtr = (int*)pointerToSharedMem; 
    pointerToSharedMem += sizeof(int); 

    this.arrayPtr = (???*)pointerToSharedMem; 
    pointerToSharedMem += sizeof(int) * FixedSizeOfArray; 
} 

Wie muss ich den Zeiger erklären, dass ich eine Eigenschaft verwenden können

public int[] MyArray 
{ 
    get 
    { 
     return some magic with this.arrayPtr; 
    } 
} 

ETA: Wenn möglich, möchte ich structs vermeiden, und ich möchte auf jeden Fall Vermeiden Sie es, Daten zu kopieren. Ich hoffte auf eine Art von Cast-Konstrukt, um einen Zeiger auf die Daten im Shared Memory zu verwenden, so dass die Daten sofort verwendet werden können (d. H. Ohne zu kopieren).

Antwort

0

In C# 2.0 und höher, ein struct kann mit einem eingebetteten Array deklariert werden, in einem unsafe Kontext:

namespace FixedSizeBuffers 
{ 
    internal unsafe struct MyBuffer 
    { 
     public fixed int fixedBuffer[128]; 
    } 

    internal unsafe class MyClass 
    { 
     public MyBuffer myBuffer = default(MyBuffer); 
    } 

    internal class Program 
    { 
     static void Main() 
     { 
      MyClass myClass = new MyClass(); 

      unsafe 
      { 
       // Pin the buffer to a fixed location in memory. 
       fixed (int* intPtr = myClass.myBuffer.fixedBuffer) 
       { 
        *intPtr = someIntValue; 
       } 
      } 
     } 
    } 
} 

http://msdn.microsoft.com/en-us/library/zycewsya(v=vs.100).aspx

+0

ist es möglich, ohne eine Struktur zu verwenden? – Harald

+0

Das ist eine gute Frage. Wahrscheinlich nicht; C# benötigt einen verwalteten Container, um den unsicheren Eintrag zu halten. Sie können diesen verwalteten Container an einer anderen Stelle in Ihrem Programm ohne Probleme referenzieren, da es * ein verwalteter Container ist. –

+0

Danke für den Code. In Ihrem Beispiel ist das Array jedoch bereits deklariert. In meinem Beispiel muss ich das Array von einem Zeiger ableiten, der auf einen Bereich im Shared Memory zeigt. – Harald

0

Ich kann mir nichts besseres vorstellen als memcpy.

[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] 
public static extern IntPtr memcpy(IntPtr dest, IntPtr src, UIntPtr count); 

private static unsafe int[] GetArray(int* ptr, uint length) 
{ 
    var ints = new int[length]; 

    fixed (int* pInts = ints) 
    { 
     memcpy(new IntPtr(pInts), new IntPtr(ptr), new UIntPtr(length)); 
    } 

    return ints; 
} 
3

Eigentlich kann ich an eine andere Antwort denken.

Dies kann sehr gut hässlich werden, wenn Sie es nicht richtig verwenden.

Vorsicht!

public unsafe class UnsafeArray 
{ 
    private readonly int* _start; 
    public readonly int Length; 

    public UnsafeArray(int* start, int enforceLength = 0) 
    { 
     this._start = start; 
     this.Length = enforceLength > 0 ? enforceLength : int.MaxValue; 
    } 

    public int this[int index] 
    { 
     get { return _start[index]; } 
     set 
     { 
      if (index >= this.Length) 
      { 
       throw new IndexOutOfRangeException(); 
      } 

      _start[index] = value; 
     } 
    } 
} 
+0

Inspiriert von dieser Antwort - danke! - Ich verwende einfach eine Set- und eine Get-Methode mit einem Index als Parameter. Es ist nicht so schön, wie ich es mir erhofft habe, aber es ist ziemlich einfach und es macht den Trick, ohne Daten zu kopieren. – Harald

+1

Freut mich zu hören. Wenn Sie den Indexer beibehalten, fungiert er als Get- und Set-Methode und erspart Ihnen etwas Schreiben, so dass es sogar mehr wie ein Array aussieht. – SimpleVar