ترتيب الأعضاء غير صحيح في بنية C#
-
22-08-2019 - |
سؤال
لدي عميل TCP، الذي يضع حزمة في البنية
using System.Runtime.InteropServices;
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct tPacket_5000_E
{
public Int16 size;
public Int16 opcode;
public byte securityCount;
public byte securityCRC;
public byte flag;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.I1)]
public byte[] blowfish;
public UInt32 seedCount;
public UInt32 seedCRC;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.I1)]
public UInt32[] seedsecurity;
}
الكود الذي أستخدمه لوضع الحزمة في البنية هو:
tPacket_5000_E packet = new tPacket_5000_E();
GCHandle pin = GCHandle.Alloc(data, GCHandleType.Pinned);
packet = (tPacket_5000_E)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(tPacket_5000_E));
pin.Free();
الآن، قبل أن أواصل يجب أن أخبرك أنني أقوم بترجمة هذا المشروع من C++ إلى C#.
هذه هي المشكلة:
آخر 3 أعضاء في tPacket_5000_E هم Int32 (لقد جربت UInt32 أيضًا)، وهو DWORD في C++.القيم قبل هؤلاء الأعضاء الثلاثة، وهي لا Int32، مساوية لتلك الموجودة في C++. (أقوم بإدخال نفس الحزمة في كل من مشروع C++ وC#).
ومع ذلك، هؤلاء الأعضاء الثلاثة لديهم قيم مختلفة.
في C++ القيم هي (صحيح):
- عدد البذور: 0x00000079
- بذرة CRC:0x000000d1
- أمن البذور:
- -[0]:0x548ac099
- -1:0x03c4d378
- -[2]:0x292e9eab
- -[3]:0x4eee5ee3
- -[4]:0x1071206e
في C# القيم هي (غير صحيح):
- عدد البذور: 0xd1000000
- بذرة CRC:0x99000000
- أمن البذور:
- -[0]:0x78548ac0
- -1:0xab03c4d3
- -[2]:0xe3292e9e
- -[3]:0x6e4eee5e
- -[4]:0x00107120
الحزمة في كلا التطبيقين متساوية
byte[] data = new byte[] {
0x25, 0x00, 0x00, 0x50, 0x00, 0x00, 0x0E, 0x10,
0xCE, 0xEF, 0x47, 0xDA, 0xC3, 0xFE, 0xFF, 0x79,
0x00, 0x00, 0x00, 0xD1, 0x00, 0x00, 0x00, 0x99,
0xC0, 0x8A, 0x54, 0x78, 0xD3, 0xC4, 0x03, 0xAB,
0x9E, 0x2E, 0x29, 0xE3, 0x5E, 0xEE, 0x4E, 0x6E,
0x20, 0x71, 0x10};
لماذا يختلف الأعضاء الثلاثة الأخيرون في البنية وكيفية إصلاحهم؟
شكرا لك مقدما!
المحلول
أتوقع أن أصل مشكلتك هو قيم البايت الثلاثة
public byte securityCount;
public byte securityCRC;
public byte flag;
يتسبب في عدم محاذاة قيم 32 بت التالية للكلمات، وتضيف مجموعتا التعليمات البرمجية (أو لا تضيف) حشوة داخلية بشكل مختلف.
أتوقع أن تبدو العبوات المختلفة كما يلي:
C++ C# ================================ ================================ [size ][opcode ] [size ][opcode ] [secCnt][secCrc][flag ][blow0 ] [secCnt][secCrc][flag ][blow0 ] [blow1 ][blow2 ][blow3 ][blow4 ] [blow1 ][blow2 ][blow3 ][blow4 ] [blow5 ][blow6 ][blow7 ][seedCou [blow5 ][blow6 ][blow7 ]..PAD... nt ][seedCRC [seedCount ] ][seedSec [seedCRC ] urity0 ][seedSec [seedSecurity0 ] urity1 ][seedSec [seedSecurity1 ] urity2 ][seedSec [seedSecurity2 ] urity3 ][seedSec [seedSecurity3 ] urity4 ] [seedSecurity4 ]
...مع إدخال C# بايت من الحشو مما يؤدي إلى إبعاد القيم اللاحقة بمقدار بايت واحد.
يمكنك تجربة استخدام
[StructLayout(LayoutKind.Sequential,Pack=1)]
قبل تعريف البنية الخاص بك، والذي يجب أن يستخدم أقل قدر ممكن من المساحة.
إتقان الهياكل في C# لديه بعض المعلومات الجيدة حول كيفية/لماذا يحدث هذا.
نصائح أخرى
وأظن أن دانيال ل هو على الطريق الصحيح في إجابته.
سأحاول إضافة البايت الرابع بعد العلم.أعتقد أن مترجم C++ الخاص بك يقوم بمحاذاة القيم على حدود الكلمات.سيؤدي ذلك إلى "محاذاة" إصدار C# أيضًا.