неправильный порядок членов в структуре C # - PullRequest
1 голос
/ 27 марта 2009

У меня есть 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 ++. Значения перед этими тремя членами, которые являются NOT Int32, равны значениям в C ++. (Я внедряю один и тот же пакет и в C ++, и в проект C #).

Однако эти три члена имеют разные значения.

в C ++ значения ( правильные ):

  1. seedCount: 0x00000079
  2. seedCRC: 0x000000D1
  3. SeedSecurity:
  4. - [0]: 0x548ac099
  5. - 1 : 0x03c4d378
  6. - [2]: 0x292e9eab
  7. - [3]: 0x4eee5ee3
  8. - [4]: ​​0x1071206e

в C # значения ( неверны ):

  1. seedCount: 0xd1000000
  2. seedCRC: 0x99000000
  3. SeedSecurity:
  4. - [0]: 0x78548ac0
  5. - 1 : 0xab03c4d3
  6. - [2]: 0xe3292e9e
  7. - [3]: 0x6e4eee5e
  8. - [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};

Нажмите здесь для получения дополнительной информации

Почему последние три члена в структуре отличаются и как их исправить?

Заранее спасибо!

Ответы [ 2 ]

11 голосов
/ 27 марта 2009

Я ожидаю, что корень вашей проблемы в том, что трехбайтовые значения

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 # содержит хорошую информацию о том, как и почему это происходит.

1 голос
/ 27 марта 2009

Я подозреваю, что Даниэль L находится на правильном пути в своем ответе.

Я бы попробовал добавить 4-й байт после флага. Я предполагаю, что ваш компилятор C ++ выравнивает значения по границам слова. Это также «выровняет» версию C #.

...