C # เทียบเท่ากับโครงสร้าง C ++ เหล่านี้คืออะไร

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;

C # เทียบเท่ากับโครงสร้าง C ++ เหล่านี้คืออะไร

ฉันกำลังย้ายโค้ดบางส่วนจาก C++ ไปยัง C# และมีปัญหาในการโยกย้ายโครงสร้างเหล่านี้ ฉันได้ลองบางสิ่งแล้ว แต่สุดท้ายฉันก็มักจะประสบปัญหาในการจัดเรียง


person Otake    schedule 25.02.2010    source แหล่งที่มา
comment
สำหรับสหภาพ โปรดดูที่ social.msdn.microsoft.com/Forums/en-US/   -  person brian beuning    schedule 08.07.2014


คำตอบ (4)


ฉันสมมติว่า 'char' ถูกใช้เป็นตัวเลข 8 บิต ถ้าเป็นเช่นนั้น ต่อไปนี้คือการแมปของคุณ:

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)

ด้วยข้อมูลนี้ มันควรจะค่อนข้างง่ายในการแปลโครงสร้างเหล่านั้น (เพียงตรวจสอบให้แน่ใจว่าคุณเก็บไว้เป็นโครงสร้างและกำหนดแอตทริบิวต์ "[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", ซึ่งจะทำให้แน่ใจได้ว่า marshaller จะเก็บข้อมูลทั้งหมดไว้ในลำดับเดียวกัน

นอกจากนี้ ฉันขอแนะนำให้ดูทั้งคลาสและแอตทริบิวต์ใน System.Runtime.InteropServices เนื่องจากมีวิธีการสองสามวิธีในการจัดเรียงข้อมูลอัตโนมัติเป็นโค้ด c/c++ (และไม่จำเป็นต้องใช้โค้ด c# ที่ "ไม่ปลอดภัย" เช่นกัน)

person Grant Peters    schedule 25.02.2010
comment
signed long และ unsigned long ควรจับคู่กับ IntPtr และ UIntPtr ตามลำดับ double* ใน C++ จะแมปกับ IntPtr หรือ double* ใน C# ซึ่งเห็นได้ชัดว่าค่าหลังอนุญาตเฉพาะในรหัสที่ไม่ปลอดภัยเท่านั้น แอ็ตทริบิวต์ StructLayout สามารถระบุ CharSet ได้ - person Sam Harwell; 13.04.2010
comment
System.Runtime.InteropServices.LayoutKind.Sequential ดูเหมือนไม่เหมาะสมสำหรับสหภาพ ซึ่งควรมี System.Runtime.InteropServices.LayoutKind.Explicit - person Ben Voigt; 08.07.2014

ดูบทความ MSDN นี้เกี่ยวกับโครงสร้างการจัดโครงสร้างด้วย PInvoid .

คีย์กำลังใช้แอตทริบิวต์ StructLayout เพื่อให้แน่ใจว่าโครงสร้างได้รับการปฏิบัติอย่างถูกต้องโดย PInrigg และแอตทริบิวต์ MarshalAs สำหรับประเภทที่ไม่เข้ากันทุกประการ

person Michael Meadows    schedule 25.02.2010
comment
ขออภัยฉันไม่ได้พูดถึง ฉันได้กำหนด StructLayout ไว้บน C# ที่เทียบเท่าแล้ว และฉันไม่ต้องการใช้ PInovo โดยพื้นฐานแล้วข้อมูลจะเข้ามาเป็นไบต์จากซ็อกเก็ต และฉันต้องการรวมข้อมูลเหล่านั้นไว้ในโครงสร้าง c# ของฉัน - person Otake; 25.02.2010
comment
หากข้อมูลมาจากเครือข่าย ฉันจะประกาศส่วนที่คงที่ของประเภท Packet เป็นโครงสร้าง C# แล้วใช้ BinaryReader บนสตรีมเครือข่ายเพื่ออ่านข้อมูลที่เหลือ การจัดการกับโครงสร้างที่มีความยาวผันแปรนั้นไม่ใช่เรื่องเล็กน้อยใน C# - person Mattias S; 25.02.2010

โพสต์อื่นๆ บางโพสต์มีข้อมูลที่ดีอยู่แล้ว ฉันคิดว่าฉันจะแบ่งปันเคล็ดลับสั้นๆ ฉันต้องผ่านปัญหาประเภทนี้เมื่อเร็ว ๆ นี้ อาจชัดเจน แต่ถ้าคุณเป็นเจ้าของโค้ดทั้งสองด้านของอินเทอร์เฟซ ฉันพบว่าการใส่ความคิดเห็นทั้งหมดยกเว้นฟิลด์เดียวและตรวจสอบให้แน่ใจว่าได้ผล จากนั้นจึงเพิ่มกลับเข้าไปทีละอย่างช้าๆ เป็นวิธีที่ปลอดภัยกว่ามากในการทำงานนี้

person Steve Sheldon    schedule 12.04.2010

ย้อนกลับไปใน .Net 2.0 วัน ฉันยังมีซ็อกเก็ตเครือข่ายและแปลงไบต์สตรีมให้เป็นโครงสร้างที่มีความหมาย ในเวลานี้ มีทางเดียวเท่านั้นที่จะทำด้วยมือด้วย BitConverter และ Buffer คลาส

ขออภัย ฉันไม่พบตัวอย่างบนเว็บอีก ดังนั้นฉันจึงถอดชั้นเรียนเก่าของฉันออก (โอ้โห นี่มันดูแก่และน่าเกลียดมาก...) อาจเนื่องมาจากการถอดเสื้อผ้าออก จึงมีข้อผิดพลาดการพิมพ์ผิดเล็กๆ น้อยๆ อยู่ภายใน แต่ควรให้แนวคิดที่ดีแก่คุณเกี่ยวกับวิธีการแก้ไขปัญหา

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 วิธีนี้ล้าสมัยแล้วจริงๆ C# 3.0 (อาจมีให้ใช้งานในเวอร์ชันก่อนหน้า ฉันเริ่มใน 3 เท่านั้น) มีการรองรับที่ยอดเยี่ยมสำหรับการแปลข้อมูลอัตโนมัติเป็นส่วนใหญ่ ฉันไม่ได้ทำอะไรที่ซับซ้อนด้วยตัวเองเพื่อให้ฟังก์ชัน c ทำงานใน c# แม้แต่โครงสร้างที่มีสตริงที่มีความยาวผันแปรก็ทำได้ง่าย - person Grant Peters; 25.02.2010
comment
ใช่ สำหรับฟังก์ชันที่คุณต้องการเข้าถึงโดย DLLImport สิ่งนี้เป็นจริง แต่ถ้าคุณมี byte[] (เช่นจากซ็อกเก็ต) ก็ไม่มีสิ่งนั้น (เท่าที่ฉันรู้) - person Oliver; 25.02.2010