Вопрос

У меня возникла небольшая проблема с использованием FieldOffset правильно с массивами. Приведенный ниже код является примером, где он не работает правильно для меня:

[StructLayout(LayoutKind.Explicit)]
public struct IndexStruct {
    [FieldOffset(0)]
    public byte[] data;

    [FieldOffset(0)]
    public short[] idx16;

    [FieldOffset(0)]
    public int[] idx32;
}

Если я, например, задаю массив с именем " data " в сериализованный байтовый массив, а затем попытайтесь извлечь данные в виде шорт, используя " idx16 " поле индексирования по-прежнему выравнивается как байт []. Это означает, что idx16 1 извлекает второй байт данных, а не второе 16-битное слово (байт 2 и 3). Если я делаю обратные индексные шорты вместо байтов, это означает, что выравнивание смещения наследуется от исходных данных. Мой вопрос, есть ли способ обойти это? Я знаю, что могу компенсировать значение индекса путем умножения на размер элемента, но есть ли другой способ?

Здесь - это ответ, который я нашел здесь в StackOverflow, но при попытке этого кода оказалось, что он не работает должным образом. Попробовал, используя модульный тест в VS со следующим кодом, но безуспешно:

[TestMethod()]
public void SumTest() {
    float[] fArr = {2.0f, 0.5f, 0.0f, 1.0f};
    MemoryStream ms = new MemoryStream();
    for (int i = 0; i < fArr.Length; i++) {
        ms.Write(BitConverter.GetBytes(fArr[i]), 0, sizeof(float));
    }
    byte[] buff = ms.ToArray();
    double expected = 3.5f;
    double actual = Sum(buff);
    Assert.AreEqual(expected, actual);
}

Заранее большое спасибо!

Это было полезно?

Решение

Проблема в том (насколько я вижу), что вы объединили ссылки массивов - так что какой бы массив не был установлен последним, победит. Когда есть массив, он использует индексатор (а не смещение в байтах) - поэтому размер не имеет значения.

Способ сделать это "правильно" (или неправильно, в зависимости от обстоятельств), вероятно, будет с небезопасным кодом - с указателем на массив - что-то вроде:

    IndexStruct s = new IndexStruct();
    s.data = new byte[] { 1, 0, 0, 0, 1, 1 };

    unsafe
    {
        fixed (short* data = s.idx16)
        {
            Console.WriteLine(data[0]); // should be 1 (little-endian)
            Console.WriteLine(data[1]); // should be 0
            Console.WriteLine(data[2]); // should be 257
        }
    }

Конечно, я не уверен, что рекомендую это - но, похоже, это то, чего вы хотите?

Мне также интересно, можете ли вы полностью удалить struct и просто использовать небезопасный доступ к byte [] напрямую:

    byte[] raw = new byte[] { 1, 0, 0, 0, 1, 1 };
    unsafe
    {
        fixed (byte* addr = raw)
        {
            short* s = (short*)addr;
            Console.WriteLine(s[0]); // should be 1
            Console.WriteLine(s[1]); // should be 0
            Console.WriteLine(s[2]); // should be 257
        }
    }

Другие советы

Ваш FieldOffset определяет, где каждый из ваших элементов данных находится внутри структуры.

Устанавливая их все в 0, вы сообщаете компилятору, что они все в позиции 0.

Второе, что я вижу, это то, что вы создаете массив байтов, шортов и целых чисел.

см .: MSDN StructLayoutAttribute

[StructLayout(LayoutKind.Explicit)]
public struct IndexStruct {
        [FieldOffset(0)]
        public byte[16] data;

        [FieldOffset(16)]
        public short idx16;

        [FieldOffset(18)]
        public int idx32;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top