Apa yang setara dengan C# dari struct C++ ini

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;

Apa yang setara dengan C# dari struct C++ ini?

Saya memigrasikan beberapa kode dari C++ ke C# dan mengalami masalah saat memigrasikan struktur ini. Saya telah mencoba beberapa hal tetapi saya selalu mengalami masalah penyusunan.


person Otake    schedule 25.02.2010    source sumber
comment
Untuk serikat pekerja, lihat social.msdn.microsoft.com/Forums/en-US/   -  person brian beuning    schedule 08.07.2014


Jawaban (4)


Saya berasumsi 'char' digunakan sebagai angka 8 bit, jika demikian, inilah pemetaan Anda:

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)

Dengan info ini seharusnya relatif mudah untuk menerjemahkan struktur tersebut (pastikan Anda menyimpannya sebagai sebuah struct dan memberinya atribut "[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", yang akan memastikan bahwa marshaller menyimpan semua data dalam urutan yang sama.

Selain itu, saya sarankan untuk melihat kelas dan atribut di System.Runtime.InteropServices karena keduanya menyediakan beberapa metode untuk mengotomatisasi penyusunan data ke kode c/c++ (dan juga tidak memerlukan kode c# yang "tidak aman").

person Grant Peters    schedule 25.02.2010
comment
signed long dan unsigned long masing-masing harus dipetakan ke IntPtr dan UIntPtr. double* di C++ akan dipetakan ke IntPtr atau double* di C#, yang terakhir jelas hanya diperbolehkan dalam kode yang tidak aman. Atribut StructLayout dapat menentukan CharSet. - person Sam Harwell; 13.04.2010
comment
System.Runtime.InteropServices.LayoutKind.Sequential tampaknya tidak sesuai untuk serikat pekerja, yang seharusnya memiliki System.Runtime.InteropServices.LayoutKind.Explicit. - person Ben Voigt; 08.07.2014

Lihat artikel MSDN ini tentang menyusun struct dengan PINvoke .

Kuncinya adalah menggunakan atribut StructLayout untuk memastikan bahwa struct diperlakukan dengan benar oleh PINvoke, dan atribut MarshalAs untuk tipe yang tidak berbaris persis.

person Michael Meadows    schedule 25.02.2010
comment
Maaf saya tidak menyebutkan; Saya sudah mendefinisikan StructLayout pada setara C# saya dan saya tidak ingin menggunakan PINvoke. Pada dasarnya data masuk sebagai byte dari soket dan saya ingin memasukkannya ke dalam struktur c# saya. - person Otake; 25.02.2010
comment
Jika data berasal dari jaringan, saya hanya akan mendeklarasikan bagian tetap dari tipe Paket sebagai struct C#, dan kemudian menggunakan BinaryReader melalui aliran jaringan untuk membaca data yang tersisa. Berurusan dengan struct dengan panjang variabel bukanlah hal yang sepele di C#. - person Mattias S; 25.02.2010

Beberapa postingan lain sudah memiliki informasi yang bagus, saya pikir saya akan membagikan tip singkatnya. Saya harus melalui masalah seperti ini baru-baru ini. Ini mungkin sudah jelas tetapi jika Anda memiliki kode untuk kedua sisi antarmuka, saya menemukan bahwa mengomentari semua kecuali satu bidang dan memastikan itu berfungsi dan kemudian menambahkannya kembali secara perlahan satu per satu adalah cara yang jauh lebih aman untuk membuat ini berfungsi.

person Steve Sheldon    schedule 12.04.2010

Kembali ke .Net 2.0 hari saya juga memiliki soket jaringan dan mengubah aliran byte menjadi struktur yang bermakna. Saat ini hanya ada satu solusi untuk melakukannya secara manual dengan BitConverter dan kelas Buffer.

Sayangnya saya tidak dapat menemukan contohnya lagi di web. Jadi aku melucuti kelas lamaku (wah, ini terlihat sangat tua dan jelek...). Mungkin karena strip down, ada beberapa kesalahan ketik kecil di dalamnya, tapi ini akan memberi Anda ide bagus tentang cara menyelesaikan masalah tersebut.

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;
        }
    }
}
person Oliver    schedule 25.02.2010
comment
-1 Metode ini benar-benar ketinggalan jaman sekarang. C# 3.0 (mungkin telah tersedia di versi sebelumnya, saya baru memulai di versi 3) memiliki dukungan yang sangat baik untuk sebagian besar mengotomatiskan terjemahan data. Saya sendiri tidak perlu melakukan sesuatu yang rumit agar fungsi c berfungsi di c#, bahkan struktur yang berisi string dengan panjang variabel pun mudah dilakukan. - person Grant Peters; 25.02.2010
comment
Ya, untuk fungsi yang ingin Anda akses melalui DLLImport, ini benar. Tetapi jika Anda memiliki byte[] (misalnya dari soket) tidak ada hal seperti itu (sejauh yang saya tahu). - person Oliver; 25.02.2010