2009-03-27 6 views
2

C++ Code:Comment mettre un tableau dans une structure en C#?

struct tPacket 
{ 
    WORD word1; 
    WORD word2; 
    BYTE byte1; 
    BYTE byte2; 
    BYTE array123[8]; 
} 

static char data[8192] = {0}; 
... 
some code to fill up the array 
... 
tPacket * packet = (tPacket *)data; 

Nous ne pouvons pas faire cela aussi facile en C#.

Veuillez noter qu'il existe un tableau dans la structure C++.

Alternativement, en utilisant this source file pourrait faire le travail pour nous, mais pas s'il y a un tableau dans la structure.

Répondre

1

Je pense que ce que vous cherchez (si vous utilisez une définition de structure similaire comme JaredPar affiché) est quelque chose comme ceci:

tPacket t = new tPacket(); 
byte[] buffer = new byte[Marshal.SizeOf(typeof(tPacket))]; 
socket.Receive(buffer, 0, buffer.length, 0); 

GCHandle pin = GCHandle.Alloc(buffer, GCHandleType.Pinned); 
t = (tPacket)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(tPacket)); 
pin.free(); 

//do stuff with your new tPacket t 
+0

En outre, vous ne devez pas mettre ce code dans un bloc dangereux. – scottm

+0

scotty2012, Merci. J'ai quelques problèmes dans l'ordre des octets, mais je vais essayer de comprendre par moi-même. Si ce n'est pas le cas, postez une autre question. Merci les deux! –

+0

Parfois, vous devez jouer avec le paramètre Pack dans les attributs de structure. Je pense que par défaut C# est de 8 octets, mais c est 4, ou quelque chose à cet effet. Je ne me souviens pas du haut de ma tête. – scottm

8

Je ne sais pas exactement ce que vous demandez. Êtes-vous en train d'essayer d'obtenir une définition de structure équivalente en C# pour une utilisation simple en C# ou à des fins d'interop (PInvoke)? Si c'est pour PInvoke la structure follownig travaillera

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 
public struct tPacket { 

    /// WORD->unsigned short 
    public ushort word1; 

    /// WORD->unsigned short 
    public ushort word2; 

    /// BYTE->unsigned char 
    public byte byte1; 

    /// BYTE->unsigned char 
    public byte byte2; 

    /// BYTE[8] 
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=8, ArraySubType=System.Runtime.InteropServices.UnmanagedType.I1)] 
    public byte[] array123; 
} 

Si vous êtes à la recherche d'une structure ancienne plaine C# qui a les mêmes caractéristiques, il est malheureusement pas possible de faire avec un struct. Vous ne pouvez pas définir un tableau en ligne d'une taille constante dans une structure C#, ni forcer le tableau à avoir une taille spécifique via un initialiseur.

Il existe deux options alternatives dans le monde géré.

Utilisez une struct qui a une méthode de création qui remplit le tableau

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 
public struct tPacket { 
    public ushort word1; 
    public ushort word2; 
    public byte byte1; 
    public byte byte2; 
    public byte[] array123; 
    public static tPacket Create() { 
     return new tPacket() { array123 = new byte[8] }; 
    } 
} 

Ou bien utiliser une classe où vous pouvez initialiser directement la variable membre de array123.

EDIT OP watns pour savoir comment convertir un octet [] en une valeur de tPacket

Malheureusement, il n'y a pas de bonne façon de le faire en C#. C++ était génial pour ce genre de tâche car il a un système de type très faible en ce sens que vous pouvez choisir d'afficher un flux d'octets en tant que structure particulière (un mauvais pointeur).

Cela peut être possible dans un code C# dangereux, mais je ne le crois pas. Essentiellement, ce que vous aurez à faire est d'analyser manuellement les octets et de les affecter aux différentes valeurs dans la structure. Ou écrivez une méthode native qui fait le casting de style C et PInvoke dans cette fonction.

+0

Hmm, d'accord, mais comment ajouter le tableau dans la structure? –

+0

@John, les deux échantillons incluent le tableau dans la structure. Je ne suis pas sûr de ce que vous demandez – JaredPar

+0

@JaredPar, le code C++ est utilisé avec la réception d'un paquet. Lorsque le paquet est reçu, le paquet variable stocke les données dans la structure tPacket et les accède plus tard.Les membres réels sont Size, Opcode, SeedCRC, SeedSecurity, EncryptedData et le fatal - blowfish, qui est le tableau. –

1

Il peut être fait avec le code dangereux aussi, même si elle limite le contexte sous lequel votre programme peut fonctionner, et, naturellement, introduit la possibilité de failles de sécurité. L'avantage est que vous transtypez directement à partir d'un tableau vers la structure à l'aide de pointeurs. Il est également sans maintenance si vous ne faites qu'ajouter ou supprimer des champs de la structure. Cependant, l'accès aux tableaux nécessite l'utilisation de l'instruction fixed puisque le GC peut toujours déplacer la structure en mémoire quand elle est contenue dans un objet.

est ici un code modifié d'un struct dangereux j'ai utilisé pour interpréter les paquets UDP:

using System; 
using System.Runtime.InteropServices; 

[StructLayout(LayoutKind.Sequential)] 
public unsafe struct UnsafePacket 
{ 
    int time; 
    short id0; 
    fixed float acc[3]; 
    short id1; 
    fixed float mat[9]; 

    public UnsafePacket(byte[] rawData) 
    { 
     if (rawData == null) 
      throw new ArgumentNullException("rawData"); 
     if (sizeof(byte) * rawData.Length != sizeof(UnsafePacket)) 
      throw new ArgumentException("rawData"); 

     fixed (byte* ptr = &rawData[0]) 
     { 
      this = *(UnsafePacket*)rawPtr; 
     } 
    } 

    public float GetAcc(int index) 
    { 
     if (index < 0 || index >= 3) 
      throw new ArgumentOutOfRangeException("index"); 
     fixed (UnsafePacket* ptr = &acc) 
     { 
      return ptr[index]; 
     } 
    } 

    public float GetMat(int index) 
    { 
     if (index < 0 || index >= 9) 
      throw new ArgumentOutOfRangeException("index"); 
     fixed (UnsafePacket* ptr = &mat) 
     { 
      return ptr[index]; 
     } 
    } 

      // etc. for other properties 
} 

Pour ce type de code, il est extrêmement important de vérifier que la longueur du tableau correspond parfaitement à la taille de la struct , sinon vous allez ouvrir pour certains débordements de tampon méchant. Comme le mot clé non sécurisé a été appliqué à la structure entière, vous n'avez pas besoin de marquer chaque méthode ou bloc de code comme étant des instructions non sécurisées.

1

Vous pouvez placer ce qui ressemble au monde extérieur comme un tableau de taille fixe dans une structure sûre en écrivant des fonctions dans la structure pour l'accès. Par exemple, voici un tableau double précision 4 x 4 fixe dans une structure sécurisée:

public struct matrix4 // 4 by 4 matrix 
{ 
    // 
    // Here we will create a square matrix that can be written to and read from similar 
    // (but not identical to) using an array. Reading and writing into this structure 
    // is slower than using an array (due to nested switch blocks, where nest depth 
    // is the dimensionality of the array, or 2 in this case). A big advantage of this 
    // structure is that it operates within a safe context. 
    // 
    private double a00; private double a01; private double a02; private double a03; 
    private double a10; private double a11; private double a12; private double a13; 
    private double a20; private double a21; private double a22; private double a23; 
    private double a30; private double a31; private double a32; private double a33; 
    // 
    public void AssignAllZeros()     // Zero out the square matrix 
    { /* code */}    
    public double Determinant()      // Common linear algebra function 
    { /* code */} 
    public double Maximum()       // Returns maximum value in matrix 
    { /* code */} 
    public double Minimum()       // Minimum value in matrix 
    { /* code */} 
    public double Read(short row, short col)  // Outside read access 
    { /* code */} 
    public double Read(int row, int col)   // Outside read access overload 
    { /* code */} 
    public double Sum()        // Sum of 16 double precision values 
    { 
     return a00 + a01 + a02 + a03 + a10 + a11 + a12 + a13 + a20 + a21 + a22 + a23 + a30 + a31 + a32 + a33; 
    } 
    public void Write(short row, short col, double doubleValue) // Write access to matrix 
    { /* code */} 
    public void Write(int row, int col, double doubleValue)  // Write access overload 
    { /* code */}    
} 
+0

Évitez de modifier les zones d'une structure dans les méthodes d'instance autres que les setters de propriétés. Exposez une propriété 'this [int, int]', ou bien des méthodes statiques qui prennent un 'Matrix4' comme paramètre' ref'. – supercat

Questions connexes