С# маленький конец или большой endian?

В документации на аппаратное обеспечение, которое позволяет нам контролировать его через UDP/IP, Я нашел следующий фрагмент:

В этом протоколе связи DWORD представляет собой данные размером 4 байта, WORD - это 2 байта данных, BYTE - это однобайтовые данные. Формат хранения данных невелик, а данные размером 4 байта (32 бита) сохраняются как: d7-d0, d15-d8, d23-d16, d31-d24; данные с двумя байтами (16 бит) хранятся как: d7-d0, d15-d8.

Мне интересно, как это переводится на С#? Должен ли я преобразовать материал, прежде чем отправлять его? Например, если я хочу отправить более 32-битное целое число или строку из 4 символов?

Ответ 1

Сам С# не определяет endianness. Однако, когда вы конвертируете в байты, вы делаете выбор. Класс BitConverter имеет IsLittleEndian поле для расскажите, как он будет себя вести, но это не дает выбора. То же самое касается BinaryReader/BinaryWriter.

My MiscUtil библиотека имеет класс EndianBitConverter, который позволяет вам определять достоверность; существуют аналогичные эквиваленты для BinaryReader/Writer. Нет руководства по использованию в Интернете. Я боюсь, но они тривиальны:)

(EndianBitConverter также имеет часть функциональности, которой нет в обычном BitConverter, который должен делать преобразования на месте в массиве байтов.)

Ответ 2

Вы также можете использовать

IPAddress.NetworkToHostOrder(...)

Короче говоря, int или long.

Ответ 3

Re little-endian, короткий ответ (для чего мне нужно что-либо сделать) "возможно, нет, но это зависит от вашего оборудования". Вы можете проверить:

bool le = BitConverter.IsLittleEndian;

В зависимости от того, что это говорит, вы можете захотеть отменить части своих буферов. В качестве альтернативы, у Jon Skeet есть преобразователи с определенными концами здесь (ищите EndianBitConverter).

Обратите внимание, что itaniums (например) являются big-endian. Большинство Интелов малоподобны.

Повторите конкретный UDP/IP...?

Ответ 4

Вам нужно знать порядок сетевого байта, а также имя процессора.

Обычно для сообщений TCP/UDP вы всегда конвертируете данные в сетевой порядок байтов, используя функцию htonsntohs, и связанные с ними функции).

Обычно порядок сети велик, но в этом случае (по какой-то причине!) коммиты мало ориентированы, поэтому эти функции не очень полезны. Это важно, поскольку вы не можете считать, что коммуникационные каналы UDP, которые они реализовали, следуют любым другим стандартам, это также затрудняет жизнь, если у вас есть архитектура большого конца, поскольку вы просто не можете обернуть все с помощью htons, как вам следует: - (

Однако, если вы исходите из архитектуры x86 x86, то вы уже малозначительны, поэтому просто отправляйте данные без преобразования.

Ответ 5

Или вы можете использовать этот код для переключения BitConverter на большой endian:

typeof (BitConverter).GetRuntimeField("IsLittleEndian").SetValue(null, false);

И чтобы вернуться к маленькому концу:

typeof (BitConverter).GetRuntimeField("IsLittleEndian").SetValue(null, true);

Ответ 6

Я играю с упакованными данными в многоадресной рассылке UDP, и мне нужно что-то переупорядочить октеты UInt16, так как я заметил ошибку в заголовке пакета (Wireshark), поэтому я сделал это:

    private UInt16 swapOctetsUInt16(UInt16 toSwap)
    {
        Int32 tmp = 0;
        tmp = toSwap >> 8;
        tmp = tmp | ((toSwap & 0xff) << 8);
        return (UInt16) tmp;
    }

В случае UInt32,

    private UInt32 swapOctetsUInt32(UInt32 toSwap)
    {
        UInt32 tmp = 0;
        tmp = toSwap >> 24;
        tmp = tmp | ((toSwap & 0xff0000) >> 8);
        tmp = tmp | ((toSwap & 0xff00) << 8);
        tmp = tmp | ((toSwap & 0xff) << 24);
        return tmp;
    }

Это просто для тестирования

    private void testSwap() {
        UInt16 tmp1 = 0x0a0b;
        UInt32 tmp2 = 0x0a0b0c0d;
        SoapHexBinary shb1 = new SoapHexBinary(BitConverter.GetBytes(tmp1));
        SoapHexBinary shb2 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt16(tmp1)));
        Debug.WriteLine("{0}", shb1.ToString());
        Debug.WriteLine("{0}", shb2.ToString());
        SoapHexBinary shb3 = new SoapHexBinary(BitConverter.GetBytes(tmp2));
        SoapHexBinary shb4 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt32(tmp2)));
        Debug.WriteLine("{0}", shb3.ToString());
        Debug.WriteLine("{0}", shb4.ToString());
    }

из которого вывод был следующим:

    0B0A: {0}
    0A0B: {0}
    0D0C0B0A: {0}
    0A0B0C0D: {0}

Ответ 7

Если вы разбираетесь и производительность не критична, рассмотрите этот очень простой код:

private static byte[] NetworkToHostOrder (byte[] array, int offset, int length)
{
    return array.Skip (offset).Take (length).Reverse ().ToArray ();
}

int foo = BitConverter.ToInt64 (NetworkToHostOrder (queue, 14, 8), 0);