Mały Endian vs Big Endian w C

Mały Endian vs Big Endian w C

W tym samouczku omówimy koncepcję endianness w komputerze. Endian oznacza zamawianie bajtów. W komputer. Gdy dane są przechowywane w pamięci, bity są przechowywane bajtem w bajcie. Bajt to jednostka danych pamięci, która składa się z grupy 8 bitów. Pamięć komputera jest dostosowalna do bajtów, więc tylko jeden bajt może być obecny w lokalizacji pamięci. Gdy dane są tylko jednym bajtem, ten bajt jest przechowywany w jednej lokalizacji pamięci. Ale gdy dane są więcej niż jeden bajt, bajty te mogą być przechowywane w lokalizacji pamięci na dwa różne sposoby.

Przykłady do zrozumienia:

int x = 513;

Dwie bajtowa reprezentacja binarna 513 to 0000001000000001.

MSB LSB
00000010 00000001

Pamięć jest adresowana bajtów. Jeden bajt jest przechowywany w jednym miejscu pamięci, a ta lokalizacja pamięci ma adres. Jeśli jeden bajt jest przechowywany na adresie „A”, następny bajt jest przechowywany na następnym adresie, którym jest „A+1” i tak dalej. Teraz bajty mogą być przechowywane w pamięci od najmłodszych bajtów do bajtów lub z bajtów z bajtów do lewej bajtów.

Tutaj adresem pamięci początkowej to „A”. Tak więc, jeśli bajty są przechowywane w pamięci od najmłodszych bajtów do bajtów w prawej, lewej bajcie ”00000010”Jest przechowywany w lokalizacji pamięci„ A ”i prawy bajt”00000001”Jest przechowywany w lokalizacji pamięci„ A+1 ”.

A - 1
A 00000010
A + 1 00000001
A + 2

Co to jest wielki endian?

Gdy najbardziej znaczący bajt jest obecny w najmniejszym miejscu pamięci, następny bajt jest przechowywany w następnym adresie pamięci i tak dalej. Ten rodzaj kolejności bajt nazywa się „Big Endian”.

Jeśli bajty są przechowywane w pamięci od najmłodszych bajtów do bajtów w lewo, prawy bajt ”00000001”Jest przechowywany w lokalizacji pamięci„ A ”i w lewym bajcie”00000010”Jest przechowywany w lokalizacji pamięci„ A+1 ”.

A - 1
A 00000001
A + 1 00000010
A + 2

Co to jest mały endian?

Gdy najmniej znaczący bajt jest przechowywany w najmniejszym miejscu pamięci, poprzedni bajt jest przechowywany w następnym adresie pamięci i tak dalej. Ten rodzaj kolejności bajt nazywa się „Little Endian”.

A - 1
A 00000010
A + 1 00000001
A + 2

Możemy sprawdzić, czy komputer jest duży endian czy mały endian przy użyciu następujących przykładów kodu C:

Przykład 1:

#włączać
void endian ()
int x = 1;
char *a = (char *) i x;
if ([0] == 1)
printf („Little Endian \ n”);
w przeciwnym razie
printf („Big Endian \ n”);

int main ()
printf („maszyna endianness =>”);
Endian ();
powrót 0;

Wyjście:

somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ gcc przykład1.C -O Przykład 1
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ ./Przykład 1
Maszyna endianness => mało endian
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $

Tutaj, jeśli liczba całkowita to dwa bajty, binarna reprezentacja 1 wynosi 00000000 00000001. Konwertujemy wskaźnik na wskaźnik char, który ma jeden bajt długi. Tak więc, jeśli uzyskujemy dostęp do pierwszej lokalizacji pamięci i otrzymamy wartość 1, oznacza to, że prawy bajt jest przechowywany w najniższej lokalizacji pamięci. To jest mała maszyna endian. W przeciwnym razie będzie to duża maszyna endian.

Przykład 2:

#włączać
Union Endian
int i;
char c [sizeof (int)];
;
int main ()
Union Endian u;
u.i = 1;
Jeśli ty.c [0] == 1)
printf („Little Endian \ n”);
w przeciwnym razie
printf („Big Endian \ n”);
powrót 0;

Wyjście:

somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ gcc przykład2.C -O Przykład 2
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ ./Przykład2
Mały Endian
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $

W tym przykładzie używamy Unii. Jeśli 1 jest przechowywany w 0th Lokalizacja tablicy, maszyna musi być mała endian. W przeciwnym razie maszyna będzie duża endian.

Problem w endianness

Komputer przechowuje i pobiera dane w tej samej endianness, w której wynik jest taki sam. Problem pojawia się w endianness, gdy dane przenoszą się z jednej maszyny do drugiej maszyny. Jeśli dwie maszyny są w innym seksie bajtowym, oznacza to, że jeden komputer używa dużego endian, a inny komputer używa małego endian. Kiedy dane przenoszą się z jednego do drugiego, pojawiają się rzeczywiste problemy. Ten problem nazywa się problemem Nuxi: ciąg „UNIX” może wyglądać jak „Nuxi” na maszynie z inną płcią bajtową.

Kolejny problem pojawia się, gdy używamy Typecast w naszym programie. Na przykład: jeśli utworzymy tablicę znaków ARR [4] i spiszniemy go do INT bajtu w rozmiarze 4, otrzymamy różne wyniki na innej maszynie endian. Omówmy to w następnym przykładzie.

Przykład 3:

#włączać
int main ()

char Arr [4] = 0x01, 0x00,0x00,0x00;
int x = *(int *) arr;
printf („0x%x \ n”, x);
powrót 0;

Wyjście:

somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ gcc przykład3.C -O Przykład3
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ ./Przykład3
0x1
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $

W tym przykładzie „ARR” jest tablicą postaci. Ty spędzamy to do 4 bajtowej całkowitej x. Jeśli skompilujemy program w małej maszynie endian, otrzymujemy wartość 0x00000001. Ale jeśli skompilujemy program w dużym komputerze endian, otrzymujemy wartość 0x01000000.

0x01 0x00 0x00 0x00
ARR [0] ARR [1] ARR [2] ARR [3]

Przykład 4:

#włączać
int main ()

char Arr [4] = 0x00, 0x00,0x00,0x01;
int x = *(int *) arr;
printf („0x%x \ n”, x);
powrót 0;

Wyjście:

somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ gcc przykład4.C -O Przykład4
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ ./Przykład4
0x1000000
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $

Ten przykład jest taki sam jak w przykładzie 3. Zmień tylko wartość, aby ją zrozumieć w prostszy sposób. Jeśli skompilujemy program w małej maszynie endian, otrzymujemy wartość 0x01000000. Ale jeśli skompilujemy program w dużym maszynie endian, otrzymujemy wartość 0x00000001.

0x00 0x00 0x00 0x01
ARR [0] ARR [1] ARR [2] ARR [3]

Gdy dane są przesyłane z jednej maszyny endian do drugiej maszyny endian, musimy odpowiednio zamienić dane. Teraz zobaczmy, jak zamienić dane w następujących przykładach.

Przykład 5:

W tym przykładzie używamy operacji bitowej, aby zamienić dane. Podczas pracy bitowej nie ma wpływu endianinowości.

#włączać
#włączać
uint32_t bajteswap (wartość uint32_t)

uint32_t wynik = 0;
wynik = wynik | (wartość i 0x000000ff) << 24;
wynik = wynik | (wartość i 0x0000ff00) << 8;
wynik = wynik | (wartość i 0x00ff0000) >> 8;
wynik = wynik | (wartość i 0xff000000) >> 24;
wynik zwrotu;

int main ()

UINT32_T Data = 0x44445555;
uint32_t resultdata = 0;
resultData = bajteSwap (dane);
printf („oryginalne dane => 0x%x \ n”, dane);
printf („konwertowane dane => 0x%x \ n”, resultData);
powrót 0;

Wyjście:

somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ gcc przykład3.C -O Przykład3
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ ./Przykład3
Oryginalne dane => 0x44445555
Konwertowane dane => 0x55554444
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $

Przykład 6:

W tym przykładzie zrobimy to samo, co w przykładzie 5. Ale tutaj używamy makr zamiast funkcji.

#włączać
#włączać
#Define Change_endianness (a) ((((uint32_t) (a) i 0xff000000) >> 24) \

|. (((uint32_t) (a) i 0x00ff0000) >> 8) \
|. (((uint32_t) (a) i 0x0000FF00) << 8) \
|. (((uint32_t) (a) i 0x000000ff) << 24))
int main ()
UINT32_T Data = 0x44445555;
uint32_t resultdata = 0;
resultData = Change_endianness (dane);
printf („oryginalne dane => 0x%x \ n”, dane);
printf („konwertowane dane => 0x%x \ n”, resultData);
powrót 0;

Wyjście:

somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ gcc przykład6.C -O Przykład6
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ ./Przykład6
Oryginalne dane => 0x44445555
Konwertowane dane => 0x55554444
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $

Przykład 7:

W tym przykładzie zrobimy to samo, co w poprzednim przykładzie. Ale tutaj używamy Unii.

#włączać
#włączać
Związek typedef

uint32_t rawdata;
Uint8_t DataBuff [4];
RawData;
Uint32_T Change_endianness (wartość uint32_t)

Zmiana rawdata, oryginalna;
Oryginalne.u32rawdata = wartość;
// Zmień wartość
Zmiana.DataBuff [0] = oryginalne.DataBuff [3];
Zmiana.DataBuff [1] = oryginalne.DataBuff [2];
Zmiana.DataBuff [2] = oryginalne.DataBuff [1];
Zmiana.DataBuff [3] = oryginalne.DataBuff [0];
powrót (zmiana.Rawdata);

int main ()
UINT32_T Data = 0x44445555;
uint32_t resultdata = 0;
resultData = Change_endianness (dane);
printf („oryginalne dane => 0x%x \ n”, dane);
printf („konwertowane dane => 0x%x \ n”, resultData);
powrót 0;

Wyjście:

somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ gcc przykład5.C -O Przykład 5
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $ ./Przykład5
Oryginalne dane => 0x44445555
Konwertowane dane => 0x55554444
somnath@somnath-virtualbox: ~/Desktop/c_prog/endian $

Kiedy wysyłamy dane przez sieć, dane są wysyłane we wspólnym formacie. Gdy dane są wysyłane przez sieć, nie znamy endiannessu nadawcy i odbiornika. Używamy więc specjalnego zamówienia, które jest duże endian. To zamówienie nazywa się „zamówieniem sieciowym”.

Jeśli nadawca jest małą maszyną endian, przekształca dane na dużą endian kolejność przed wysłaniem danych. Jeśli odbiornik jest małą maszyną endian, przekształca dane w mały format endian po otrzymaniu danych.

Kiedy wysyłamy dane do sieci, używane są następujące makra:

HTONS () - „Host to Network Short”

htonl () - „host to Network Long”

ntohs () - „Sieć do hostowania krótkiego”

ntohl () - „Sieć do hostowania długiego”

HTONS () - To makro jest odczytywane jako „host do sieci krótkiej”. Bajty o wartości 16-bitowej wartości Unsigned powinny być zmienione jak następujące:

Zamówienie procesora -> Zamówienie sieci.

hton () - To makro jest odczytywane jako „host to sieć długi”. 32-bitowe bajty wartości niepodpisanej powinny być zmienione jak następujące:

Zamówienie procesora -> Zamówienie sieci.

ntohs () - To makro jest odczytywane jako „sieć do hostów krótko”. Bajty o wartości 16-bitowej wartości Unsigned powinny być zmienione jak następujące:

Zamówienie sieci -> Zamówienie procesora.

ntohl () - To makro jest odczytywane jako „sieć do hosta”. 32-bitowe bajty wartości niepodpisanej powinny być zmienione jak następujące:

Zamówienie sieci -> Zamówienie procesora.

Wniosek

W tym samouczku nauczyliśmy się szczegółów o endianness w komputerze. Wygląda na to, że stosowanie jednego podejścia endianness na drugim nie ma żadnej przewagi. Oba są nadal wykorzystywane przez różne architektury. Większość komputerów osobistych i laptopów wykorzystuje dziś małe end-endijne procesory (i ich klony), dzięki czemu mała endian jest główną architekturą komputerów komputerowych.