C#中封送处理期间的字节序列问题

Bytes sequence problem during Marshaling in C#

我想用我的笔记本电脑与MES(制造执行系统)进行通信。 当我序列化数据(结构类型)时,发生了一些事情。 下面的代码是我所做的:

[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct DataPackage
{
    public int a;
    public ushort b;
    public byte c;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)] public string d;
}
class Program
{
    static void Main(string[] args)
    {
        DataPackage pack1 = new DataPackage();
        pack1.a = 0x33333301;
        pack1.b = 200;
        pack1.c = 21;
        pack1.d = "hello";
        byte[] pack1_serialized = getBytes(pack1);
        Console.WriteLine(BitConverter.ToString(pack1_serialized));


        byte[] getBytes(DataPackage str)
        {
            int size = Marshal.SizeOf(str);
            byte[] arr = new byte[size];

            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(str, ptr, true);
            Marshal.Copy(ptr, arr, 0, size);
            Marshal.FreeHGlobal(ptr);
            return arr;
        }
    }
}

结果如下:

我希望结果是这样的:

33-33-33-01-00-C8-15-68-65-6C-6C-6F

所以问题是:

  1. 为什么uint / ushort类型的数据编组后是反的?
  2. 有没有其他方法可以按我想要的顺序发送数据?
  3. 为什么字符串“hello”中的最后一个单词“o”在字节数组中消失了?

谢谢。

1 - 因为您的预期结果是大端,而您的系统似乎使用小端,所以字节顺序与您的预期基本上相反。

2- 最简单的方法是在编组之前将您的数字“转换”为大端(即以产生所需结果的方式更改它们,同时使用小端转换它们),例如:

 static int ToBigEndianInt(int x) {
    if (!BitConverter.IsLittleEndian)
        return x; // already fine
    var ar = BitConverter.GetBytes(x);
    Array.Reverse(ar);
    return BitConverter.ToInt32(ar, 0);
 }

static ushort ToBigEndianShort(ushort x) {
    if (!BitConverter.IsLittleEndian)
        return x; // already fine
    var ar = BitConverter.GetBytes(x);
    Array.Reverse(ar);
    return BitConverter.ToUInt16(ar, 0);
}

然后:

pack1.a = ToBigEndianInt(0x33333301);
pack1.b = ToBigEndianShort(200);

请注意,这种转换方式效率不高,如果您需要更多性能,可以通过一些位操作来实现。

3 - 因为字符串以 null 终止,并且此 null 终止符计入 SizeConst。因为你有 5,所以你的字符串将有 4 个字符 + 1 个空终止符。只需增加 SizeConst = 6(由于 Pack = 4,可能会在末尾添加额外的零)。