C # little endian или big endian?
-
03-07-2019 - |
Вопрос
В документации к оборудованию, которое позволяет нам управлять им через UDP / IP, Я нашел следующий фрагмент:
В этом протоколе связи DWORD - это 4-байтовые данные, WORD - это 2-байтовые данные, BYTE - это однобайтовые данные. Формат хранения имеет порядок байтов, то есть данные размером 4 байта (32 бита) хранятся как: d7-d0, d15-d8, d23-d16, d31-d24; двухбайтовые (16-битные) данные хранятся в виде: d7-d0, d15-d8.
Мне интересно, как это переводится на C #? Должен ли я конвертировать вещи перед отправкой? Например, если я хочу отправить 32-разрядное целое число или строку из 4 символов?
Решение
Сам C # не определяет порядок байтов. Однако, когда вы конвертируете в байты, вы делаете выбор. BitConverter имеет класс IsLittleEndian , чтобы сообщить вам, как он будет себя вести, но не дает выбора. То же самое касается BinaryReader / BinaryWriter.
Моя библиотека MiscUtil имеет класс EndianBitConverter, который позволяет определять порядок байтов; Есть аналогичные эквиваленты для BinaryReader / Writer. Боюсь, в Интернете нет руководства по использованию, но они тривиальны:)
(EndianBitConverter также имеет часть функциональности, которой нет в обычном BitConverter, которая должна выполнять преобразования на месте в байтовом массиве.)
Другие советы
Вы также можете использовать
IPAddress.NetworkToHostOrder(...)
Для коротких, int или long.
Re-little-endian, краткий ответ (для этого мне нужно что-то сделать) - "вероятно, нет", но это зависит от вашего оборудования ". Вы можете проверить с помощью:
bool le = BitConverter.IsLittleEndian;
В зависимости от того, что это говорит, вы можете обратить вспять части ваших буферов. Кроме того, у Джона Скита есть конвертеры с прямым порядком байтов здесь (ищите EndianBitConverter). р>
Обратите внимание, что itaniums (например) имеют порядок байтов. Большинство Intel имеют младший порядок.
Re конкретный UDP / IP ...?
Вы должны знать о порядке байтов в сети, а также о порядке байтов процессора.
Обычно для связи TCP / UDP вы всегда конвертируете данные в сетевой порядок байтов, используя htons
(и ntohs
, и связанные с ними функции).
Обычно сетевой порядок имеет порядок с прямым порядком байтов, но в этом случае (по какой-то причине!) константы имеют младший порядок байтов, поэтому эти функции не очень полезны. Это важно, поскольку вы не можете предполагать, что внедренные ими UDP-соединения соответствуют каким-либо другим стандартам, это также усложняет жизнь, если у вас архитектура с прямым порядком байтов, поскольку вы просто не можете обернуть все с помощью htons
, как вы следует: - (
Однако если вы работаете с архитектурой Intel x86, значит, вы уже в порядке байтов, поэтому просто отправляйте данные без преобразования.
Если вы анализируете и производительность не критична, рассмотрите этот очень простой код:
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);
Я играю с упакованными данными в UDP Multicast, и мне нужно было что-то переставить в октетах 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}