Kiedy Endianess staje się czynnikiem?

Endianness z tego, co rozumiem, jest wtedy, gdy bajty składające się na słowo wielobajtowe różnią się w kolejności, przynajmniej w najbardziej typowym przypadku. Tak, że 16-bitowa liczba całkowita może być przechowywana jako 0xHHLL lub 0xLLHH.

Zakładając, że nie mam tego błędu, chciałbym wiedzieć, kiedy Endianess staje się głównym czynnikiem podczas wysyłania informacji między dwoma komputerami, gdzie Endian może lub nie może być inny.

  • Jeśli prześlę krótką liczbę całkowitą 1, w postaci z tablicy znaków i bez korekty, czy jest ona odbierana i interpretowana jako 256?

  • Jeśli rozłożę i przekomponuję krótką liczbę całkowitą używając następującego kodu, czy endianness nie będzie już czynnikiem?

    // Sender:
    for(n=0, n < sizeof(uint16)*8; ++n) {
        stl_bitset[n] = (value >> n) & 1;
    };
    
    // Receiver:
    for(n=0, n < sizeof(uint16)*8; ++n) {
        value |= uint16(stl_bitset[n] & 1) << n;
    };
    
  • czy istnieje standardowy sposób kompensowania nieskończoności?
Z góry dzięki!
Author: Andrew Neely, 2011-08-24

8 answers

Mówiąc abstrakcyjnie, endianness jest właściwością reinterpretacji zmiennej jako tablicy znaków.

Praktycznie ma to znaczenie dokładnie wtedy, gdy read() od I write() do zewnętrznego strumienia bajtów (np. pliku lub gniazda). Lub, mówiąc abstrakcyjnie, endianness ma znaczenie, gdy serializujesz dane (zasadniczo dlatego, że dane serializowane nie mają systemu typów i składają się tylko z głupich bajtów); a endianness nie ma znaczenia w twojego programowania język, ponieważ język działa tylko na wartościach , a nie na reprezentacjach. Przechodząc od jednego do drugiego, musisz zagłębić się w szczegóły.

Do dowcipu-pisanie:

uint32_t n = get_number();

unsigned char bytesLE[4] = { n, n >> 8, n >> 16, n >> 24 };  // little-endian order
unsigned char bytesBE[4] = { n >> 24, n >> 16, n >> 8, n };  // big-endian order

write(bytes..., 4);
Tutaj moglibyśmy po prostu powiedzieć, reinterpret_cast<unsigned char *>(&n), a wynik zależałby od endianness systemu.

I czytanie:

unsigned char buf[4] = read_data();

uint32_t n_LE = buf[0] + buf[1] << 8 + buf[2] << 16 + buf[3] << 24; // little-endian
uint32_t n_BE = buf[3] + buf[2] << 8 + buf[1] << 16 + buf[0] << 24; // big-endian

Ponownie, tutaj moglibyśmy powiedzieć, uint32_t n = *reinterpret_cast<uint32_t*>(buf), a wynik zależałby od maszyny endianness.


Jak widzisz, z typami całkowymi nigdy nie musisz znać endianness własnego systemu, tylko strumienia danych, jeśli używasz algebraicznych operacji wejścia i wyjścia. W przypadku innych typów danych, takich jak double, problem jest bardziej skomplikowany.

 48
Author: Kerrek SB,
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
2011-09-08 13:55:51

Dla przypomnienia, jeśli przesyłasz dane między urządzeniami, powinieneś prawie zawsze używać sieci-bajtów-zamawiania z ntohl, htonl, ntohs, htons. Konwertuje do sieciowego standardu kolejności bajtów dla Endianess niezależnie od tego, czego używa Twój system i system docelowy. Oczywiście oba systemy powinny być tak zaprogramowane - ale zazwyczaj są one w scenariuszach sieciowych.

 35
Author: John Humphreys - w00te,
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
2017-11-04 15:17:29
  1. Nie, chociaż masz rację. To, czego ci brakuje, to fakt, że chociaż zwykle jest to połączenie szeregowe, połączenie sieciowe (przynajmniej większość połączeń sieciowych) nadal gwarantuje poprawną endianess na poziomie oktetu (bajtów) - tzn. jeśli wyślesz bajt o wartości 0x12 na małej maszynie endian, to nadal będzie odbierane jako 0x12 na dużej maszynie endian.

    Patrząc na krótki, jeśli spojrzeć na liczbę w systemie szesnastkowym, to prawdopodobnie pomóc. Informatyka zaczyna się jako 0x0001. Dzielisz go na dwa bajty: 0x00 0x01. Po otrzymaniu będzie to odczytywane jako 0x0100, co okazuje się być 256.

  2. Ponieważ sieć ma do czynienia z endianess na poziomie oktetu, zwykle trzeba tylko kompensować kolejność bajtów, a nie bitów wewnątrz bajtów.

  3. Prawdopodobnie najprostszą metodą jest użycie htons/htonl podczas wysyłania i ntohs/ntohl podczas odbierania. Gdy/jeśli to nie wystarczy, istnieje wiele alternatyw, takich jak XDR, ASN.1, CORBA IIOP, bufory protokołu Google itp.

 7
Author: Jerry Coffin,
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
2011-08-24 17:56:29

"standardowym sposobem" kompensacji jest to, że pojęcie "sieciowego porządku bajtów" zostało zdefiniowane, prawie zawsze (AFAIK) jako big endian.

Zarówno nadawcy, jak i odbiorcy znają protokół wire i w razie potrzeby konwertują go przed wysyłką i po odbiorze, aby dać aplikacjom odpowiednie dane. Ale to tłumaczenie dzieje się wewnątrz Twojej warstwy sieciowej , a nie w twoich aplikacjach.

 6
Author: Ray Toal,
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
2011-08-24 17:52:44

Obie endianki mają przewagę, o której wiem:

  1. Big-endian jest koncepcyjnie łatwiejszy do zrozumienia, ponieważ jest podobny do naszego pozycyjnego systemu liczbowego: od najbardziej znaczącego do najmniej znaczącego.
  2. Little-endian jest wygodny przy ponownym użyciu referencji pamięci dla wielu rozmiarów pamięci. Mówiąc najprościej, jeśli masz wskaźnik do little-endian unsigned int*, ale wiesz, że przechowywana tam wartość to unsigned char*.
 6
Author: amoss,
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
2011-08-30 17:46:57

Endianness jest zawsze problemem. Niektórzy powiedzą, że jeśli wiesz, że każdy host podłączony do sieci działa ten sam system operacyjny itp., nie będziesz miał problemów. Zawsze musisz opublikować specyfikację, która określa dokładny format danych on-wire. Może to być dowolny format, ale każdy punkt końcowy musi zrozumieć format i być w stanie go poprawnie zinterpretować.

Ogólnie, protokoły używają big-endian dla wartości liczbowych, ale ma to ograniczenia, jeśli każdy nie jest zgodny z IEEE 754 itp. Jeśli możesz wziąć na siebie koszty, użyj XDR (lub ulubionego rozwiązania) i bądź bezpieczny.

 5
Author: No One in Particular,
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
2011-08-24 17:49:54

Oto kilka wytycznych dla kodu neutralnego dla języka C/C++. Oczywiście są one napisane jako "zasady, których należy unikać"... więc jeśli kod ma te "cechy", może być podatny na błędy związane z endianem !! (to jest z mojego artykułu o Endianness opublikowanego w Dr Dobbs)

  1. Unikaj używania związków, które łączą różne wielobajtowe typy danych. (układ związków może mieć różne porządki związane z endianem)

  2. Unikaj dostępu do tablic bajtowych poza typem danych bajtowych. (order tablica bajtów ma kolejność endian)

  3. Unikaj używania pól bitowych i masek bajtów (ponieważ układ pamięci zależy od endianess, maskowanie bajtów i wybór pól bitowych jest wrażliwe na endian)

  4. Unikaj przerzucania wskaźników z typu wielobajtowego na inne typy bajtów.
    (gdy wskaźnik jest rzucany z jednego typu do drugiego, endianness źródła (tj. Pierwotny cel) zostaje utracony, a późniejsze przetwarzanie może być niepoprawne)

 4
Author: el rack,
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
2011-08-24 23:50:25

Nie powinieneś się martwić, chyba że jesteś na granicy systemu. Normalnie, jeśli mówisz o stl, już przekroczyłeś tę granicę.

Zadaniem protokołu serializacji jest wskazanie / określenie, w jaki sposób seria bajtów może zostać przekształcona w typ, który wysyłasz, W Typ wbudowany lub niestandardowy.

Jeśli mówisz tylko o wbudowanym, możesz wystarczyć z maszynową abstrakcją dostarczoną przez narzędzia dostarczone przez twoje środowisko]

 3
Author: xtofl,
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
2011-08-24 17:54:19