2010-02-25 5 views
4
typedef union _Value { 
    signed char c; 
    unsigned char b; 
    signed short s; 
    unsigned short w; 
    signed long l; 
    unsigned long u; 
    float   f; 
    double  *d; 
    char   *p; 
} Value; 


typedef struct _Field { 
WORD nFieldId; 
BYTE bValueType; 
Value Value; 
} Field; 


typedef struct _Packet { 
WORD nMessageType; 
WORD nSecurityType; 
BYTE bExchangeId; 
BYTE bMarketCenter; 
int  iFieldCount; 
char cSymbol[20]; 
    Field FieldArr[1]; 

} Packet; 

Quels sont les équivalents C# de ces structures C++?Quels sont les équivalents C# de ces structures C++

Je migre du code de C++ vers C# et rencontre des problèmes pour migrer ces structures. J'avais essayé quelques petites choses mais j'ai toujours eu des problèmes de triage.

+0

Pour l'union, voir http://social.msdn.microsoft.com/Forums/en-US/60150e7b-665a-49a2-8e2e-2097986142f3/c-equivalent-to-c-union?forum=csharplanguage –

Répondre

12

Je suppose que le « char » est utilisé comme numéro 8 bits, si oui, alors voici les correspondances: vous êtes

signed char c; -> SByte c; 
unsigned char b; -> Byte  b; 
signed short s; -> Int16 s; 
unsigned short w; -> UInt16 w; 
signed long l; -> Int32 l; 
unsigned long u; -> UInt32 u; 
float   f; -> Single f; (though 'float' still works) 
double  *d; -> Double d; (was this meant to be a pointer???) 
char   *p; -> String s; (assuming its a string here, in the marshaling you can tell it whether it is ASCII or wide char format) 

Avec cette information, il devrait être relativement facile pour traduire ces strucutres (assurez-vous simplement de les conserver en tant que structure et donnez-lui l'attribut "[System.Runtime.InteropServices.StructLayout (System.Runtime.InteropServices.LayoutKind.Sequential)]", ce qui garantira que le marshaller toutes les données dans le même ordre

Aussi, je recommande regarder à travers gh les deux classes et attributs dans System.Runtime.InteropServices car ils fournissent pas mal de méthodes pour automatiser le marshaling des données en code c/C++ (et cela ne nécessite pas non plus de code C# "non sécurisé").

+0

'signed long' et' unsigned long' devraient correspondre à 'IntPtr' et' UIntPtr', respectivement."double *" en C++ sera mappé sur "IntPtr" ou "double *" en C#, ce dernier n'est évidemment autorisé qu'en code non sécurisé. L'attribut 'StructLayout' peut spécifier le' CharSet'. –

+1

'System.Runtime.InteropServices.LayoutKind.Sequential' semble inapproprié pour une union, qui devrait avoir' System.Runtime.InteropServices.LayoutKind.Explicit'. –

0

Voir this MSDN article sur les structures de marshaling avec PInvoke. La clé utilise l'attribut StructLayout pour s'assurer que la structure est traitée correctement par PInvoke et l'attribut MarshalAs pour les types qui ne correspondent pas exactement.

+0

Désolé je n'ai pas mentionné; J'ai déjà défini StructLayout sur mes équivalents C# et je ne veux pas utiliser PInvoke. Fondamentalement, les données sont entrantes comme des octets d'une socket et je veux les rassembler dans mes structures C#. – Otake

+1

Si les données proviennent du réseau, je déclare simplement la partie fixe du type Packet en tant que structure C#, puis utilise un BinaryReader sur le flux réseau pour lire les données restantes. Traiter des structures de longueur variable est non trivial en C#. –

-1

Retour à. Net 2.0 jours j'avais aussi un socket réseau et de convertir le flux d'octets dans une structure significative. A cette époque, il y avait la seule solution pour le faire à la main avec BitConverter et Buffer classe.

Malheureusement je ne pouvais pas trouver l'exemple sur le web à nouveau. J'ai donc dépouillé ma vieille classe (ça alors, ça a l'air si vieux et si moche ...). Peut-être en raison de la suppression, il y a quelques petites erreurs typo dedans, mais cela devrait vous donner une bonne idée sur la façon d'accomplir le problème.

using System; 
using System.Collections.Generic; 
using System.Text; 

namespace VehicleSpeedTracer 
{ 
    public class Datagram 
    { 
     //Offsets im ByteArray 
     private const int SizeOffset = 0; 
     private const int TimeOffset = SizeOffset + sizeof(uint); 
     private const int SpeedOffset = TimeOffset + sizeof(double); 
     private const int UnitOffset = SpeedOffset + sizeof(char); 
     private const int UnitMaxSize = (int)MaxSize - UnitOffset; 

     //Daten Current 
     public const uint MaxSize = 128; 
     public TimeSpan CurrentTime; 
     public double CurrentSpeed; 
     public string Unit; 

     public uint Size 
     { 
      get { return MaxSize - (uint)UnitMaxSize + (uint)Unit.Length; } 
     } 

     public Datagram() 
     { 
     } 

     public Datagram(Datagram Data) 
     { 
      CurrentTime = Data.CurrentTime; 
      CurrentSpeed = Data.CurrentSpeed; 
      Unit = Data.Unit; 
     } 

     public Datagram(byte[] RawData) 
     { 
      CurrentTime = TimeSpan.FromSeconds(GetDouble(RawData, TimeOffset)); 
      CurrentSpeed = GetDouble(RawData, SpeedOffset); 
      Unit = GetString(RawData, UnitOffset, (int)(GetUInt(RawData, SizeOffset) - UnitOffset)); 
     } 

     public override string ToString() 
     { 
      return this.CurrentTime.Hours.ToString().PadLeft(2, '0') + ":" + 
        this.CurrentTime.Minutes.ToString().PadLeft(2, '0') + ":" + 
        this.CurrentTime.Seconds.ToString().PadLeft(2, '0') + "." + 
        this.CurrentTime.Milliseconds.ToString().PadLeft(3, '0') + " " + 
        this.Unit; 
     } 

     public static implicit operator byte[](Datagram Data) 
     { 
      byte[] RawData; 
      RawData = new byte[Data.Size]; 
      SetUInt(RawData, SizeOffset, Data.Size); 
      SetDouble(RawData, TimeOffset, Data.CurrentTime.TotalDays); 
      SetDouble(RawData, SpeedOffset, Data.CurrentSpeed); 
      SetString(RawData, UnitOffset, Data.Unit); 

      return RawData; 
     } 

     #region Utility Functions 
     // utility: get a uint from the byte array 
     private static uint GetUInt(byte[] aData, int Offset) 
     { 
      return BitConverter.ToUInt32(aData, Offset); 
     } 

     // utility: set a uint into the byte array 
     private static void SetUInt(byte[] aData, int Offset, uint Value) 
     { 
      byte[] buint = BitConverter.GetBytes(Value); 
      Buffer.BlockCopy(buint, 0, aData, Offset, buint.Length); 
     } 

     // utility: get a ushort from the byte array 
     private static ushort GetUShort(byte[] aData, int Offset) 
     { 
      return BitConverter.ToUInt16(aData, Offset); 
     } 

     // utility: set a ushort into the byte array 
     private static void SetUShort(byte[] aData, int Offset, int Value) 
     { 
      byte[] bushort = BitConverter.GetBytes((short)Value); 
      Buffer.BlockCopy(bushort, 0, aData, Offset, bushort.Length); 
     } 

     // utility: get a double from the byte array 
     private static double GetDouble(byte[] aData, int Offset) 
     { 
      return BitConverter.ToDouble(aData, Offset); 
     } 

     // utility: set a double into the byte array 
     private static void SetDouble(byte[] aData, int Offset, double Value) 
     { 
      byte[] bushort = BitConverter.GetBytes(Value); 
      Buffer.BlockCopy(bushort, 0, aData, Offset, bushort.Length); 
     } 

     // utility: get a unicode string from the byte array 
     private static string GetString(byte[] aData, int Offset, int Length) 
     { 
      String sReturn = Encoding.ASCII.GetString(aData, Offset, Length); 
      return sReturn; 
     } 

     // utility: set a unicode string in the byte array 
     private static void SetString(byte[] aData, int Offset, string Value) 
     { 
      byte[] arr = Encoding.ASCII.GetBytes(Value); 
      Buffer.BlockCopy(arr, 0, aData, Offset, arr.Length); 
     } 
     #endregion 
    } 

    public delegate void DatagramEventHandler(object sender, DatagramEventArgs e); 

    public class DatagramEventArgs : EventArgs 
    { 
     public Datagram Data; 

     public DatagramEventArgs(Datagram Data) 
     { 
      this.Data = Data; 
     } 
    } 
} 
+0

-1 Cette méthode est vraiment datée maintenant. C# 3.0 (peut-être était disponible dans les versions antérieures, j'ai seulement commencé en 3) a un excellent support pour la plupart de l'automatisation de la traduction des données. Je n'ai pas eu à faire moi-même quelque chose de complexe pour obtenir une fonction c en C#, même les structures contenant des chaînes de longueur variable sont faciles à faire. –

+0

Oui, pour une fonction à laquelle vous voulez accéder par DLLImport, ceci est vrai. Mais si vous avez un octet [] (par exemple d'une socket) il n'y a pas une telle chose (pour autant que je sache). – Oliver

0

Certains des autres messages ont déjà d'excellentes informations, je pensais que je voudrais partager un conseil rapide. J'ai dû passer par ce genre de problème récemment. Cela peut sembler évident, mais si vous possédez le code des deux côtés de l'interface, j'ai trouvé que commenter tous les champs sauf les uns et s'assurer que cela fonctionne et les rajouter lentement un à un était une façon beaucoup plus sûre de fonctionner.

Questions connexes