C # little endian czy big endian?

W dokumentacji sprzętu, który pozwala nam sterować nim poprzez UDP / IP, Znalazłem następujący fragment:

W tym protokole komunikacyjnym DWORD to 4 bajty danych, WORD to 2 bajty danych, Bajt jest pojedynczym bajtem danych. Format zapisu jest mały endian, mianowicie 4 bajty (32-bitowe) dane są przechowywane jako: d7-d0, d15-D8, d23-d16, d31-D24; podwójne bajty (16-bitowe) dane są przechowywane jako: d7-d0 , D15-d8.

Zastanawiam się jak to się przekłada na C#? Czy muszę konwertować rzeczy przed wysłaniem? Na przykład, jeśli chcę wysłać 32-bitową liczbę całkowitą lub 4-znakowy ciąg znaków?

Author: GEOCHET, 2008-10-20

6 answers

C# samo w sobie nie definiuje endianness. Jednak za każdym razem, gdy konwertujesz na bajty, dokonujesz wyboru. Klasa BitConverter ma pole IsLittleEndian , aby powiedzieć Ci, jak się zachowa, ale nie daje wyboru. To samo dotyczy BinaryReader / BinaryWriter.

My MiscUtil biblioteka posiada klasę EndianBitConverter, która pozwala zdefiniować endianness; istnieją podobne odpowiedniki dla BinaryReader/Writer. No Online usage guide I ' m afraid, ale są banalne:)

(EndianBitConverter ma również pewną funkcjonalność, która nie jest obecna w normalnym Bitconverterze, która ma wykonywać konwersje na miejscu w tablicy bajtów.)

 72
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-20 10:21:02

Możesz również użyć

IPAddress.NetworkToHostOrder(...)

Na krótko, int lub długo.

 43
Author: Jan Bannister,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-20 10:29:58

Re little-endian, krótka odpowiedź (Czy muszę cokolwiek zrobić) brzmi "prawdopodobnie nie, ale to zależy od Twojego sprzętu". Możesz sprawdzić za pomocą:

bool le = BitConverter.IsLittleEndian;

W zależności od tego, co to mówi, możesz chcieć odwrócić części swoich buforów. Alternatywnie, Jon Skeet ma Konwertery specyficzne-endian tutaj (poszukaj EndianBitConverter).

Zauważ, że jest to np. big-endian. Większość Intelów jest małoindyjska.

Re specyficzne UDP / IP...?

 10
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-20 10:20:04

Musisz wiedzieć o sieciowej kolejności bajtów oraz endian-ness procesora.

Zazwyczaj dla komunikatorów TCP / UDP, zawsze konwertujesz dane do sieciowej kolejności bajtów za pomocą htons function (and ntohs, and their related functions).

Normalnie porządek sieci jest big-endian, ale w tym przypadku (z jakiegoś powodu!) komunikator jest mało endian, więc funkcje te nie są zbyt użyteczne. Jest to ważne, ponieważ nie można zakładać, że zaimplementowane przez nich komunikatory UDP spełniają inne standardy, to również utrudnia życie, jeśli masz architekturę big-endian, ponieważ po prostu nie możesz owijać wszystkiego htons tak, jak powinieneś: - (

Jeśli jednak pochodzisz z architektury intel x86, to jesteś już little-endian, więc po prostu wyślij dane bez konwersji.

 3
Author: gbjbaanb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-05 10:48:22

Jeśli analizujesz i wydajność nie jest krytyczna, rozważ ten bardzo prosty kod:

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);
 0
Author: mafu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-08 10:38:59

Bawię się spakowanymi danymi w UDP Multicast i potrzebowałem czegoś do zmiany kolejności oktetów UInt16, ponieważ zauważyłem błąd w nagłówku pakietów (Wireshark), więc zrobiłem to:

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

W przypadku 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;
    }

To tylko do testów

    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());
    }

Z którego wyjścia było to:

    0B0A: {0}
    0A0B: {0}
    0D0C0B0A: {0}
    0A0B0C0D: {0}
 0
Author: Marko Samirić,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-10 20:25:11