2012-07-10 17 views
11

Uruchomiłem następujący program na maszynie Little-Endian [LE] [Linux, procesor Intel]. Nie jestem w stanie wyjaśnić 3 wyników w poniższym fragmencie kodu. Ponieważ maszyna jest LE, wartość a jest przechowywana jako 0x78563412. Podczas drukowania wyświetla rzeczywistą wartość. Ponieważ jest to maszyna LE, oczekuję, że ntohl() będzie operacją "no-op" i wyświetlą ją 0x78563412. Oczekuję jednak, że 0x12345678 dla drugiej deklaracji wydruku zawierającej htonl(). Czy ktoś może mi pomóc zrozumieć, dlaczego są one takie same?To samo wyjście dla htonl() i ntohl() na liczbach całkowitych

int main() 
{ 
    int a = 0x12345678; 

    printf("Original - 0x%x\n", (a)); 
    printf("Network - 0x%x\n", htonl(a)); 
    printf("Host - 0x%x\n", ntohl(a)); 

    return 0; 
} 

wyjściowa:

Original - 0x12345678 
Network - 0x78563412 
Host - 0x78563412 

Odpowiedz

23

Od jego maszynie LE, spodziewam ntohl() być no-op

że to pomyłka. Kolejność bajtów sieci to big-endian, kolejność bajtów hosta to little-endian. W związku z tym zarówno ntohl, jak i htonl zwracają wersję wejściową z zamianą bajtów.

Pamiętaj, punkt htonl jest to, że można przyjąć liczbę całkowitą od gospodarza, a następnie napisać:

int i = htonl(a); 

a wynik jest, że pamięć o i, kiedy interpretować za pomocą Network Byte Order, ma tę samą wartość, co a. Stąd, jeśli napiszesz reprezentację obiektu i do gniazda, a czytnik na drugim końcu oczekuje 4-bajtowej liczby całkowitej w kolejności bajtów sieciowych, to odczyta wartość a.

i wyświetlacz 0x78563412

Czy to, co ma pisać? Jeśli ntohl byłaby funkcją "no-op" (a raczej funkcją identyfikacji), to trzecia linia koniecznie wydrukowałaby to samo co pierwsza linia, ponieważ miałabyś ntohl(a) == a. To, co dzieje się na implementacji big-endian, gdzie swój program drukuje:

Original - 0x12345678 
Network - 0x12345678 
Host - 0x12345678 
+0

Jak wspomniano poniżej, poniżej oczekiwałem, że następujące zachowanie zawsze będzie prawdziwe: 'x == htonl (ntohl (x))'. Ale tak się nie dzieje i twoje wyjaśnienie było bardzo pomocne. – Bhaskar

+2

@Bhaskar: Punkt Briana Roacha jest również ważny, a następnie: nigdy nie obliczałeś 'htonl (ntohl (a))'. Obliczono 'htonl (a)' i 'ntohl (a)'. –

+0

dziękuję bardzo! Doskonałe wyjaśnienie – Skully

5

Ponieważ jesteś przejazdem a przez wartość i dlatego nie zmienia się przez jedną z tych funkcji.

Drukujesz, co htonl() i ntohl() powraca powracając.

Edytuj, aby dodać: Brakowało mi miejsca, w którym wydawało Ci się, że nie chcesz. To nie jest. Obie będą robić dokładnie to samo na maszynie LE; odwrócić kolejność bajtów. ntohl() spodziewa się, aby być przekazując mu bajt sieci uporządkowanej int

9

htonl i ntohl są dokładnie te same funkcje. Mają one zadowolić htonl(ntohl(x)) == x. Są one inaczej nazwane tylko dla dokumentacji (wyraźnie mówisz, że konwertujesz z hosta do sieci lub w inny sposób, nawet jeśli jest taki sam).Tak więc, na maszynie z małym endianem, obaj wykonują zamiany bajtów, a na maszynie z dużymi endianami oboje są no-opami.

+5

Na hipotetycznej implementacji "głupiego endianu" C, w której bajty nie są ani big-endianami (uporządkowanymi '4321') ani little-endian (zamówionymi' 1234'), ale uporządkowanymi na przykład '3214', nadal byś miał 'htonl (ntohl (x))', ale 'htonl' i' ntohl' nie robią tego samego, będą to 8-bitowe obroty w przeciwnych kierunkach. Mam nadzieję, że taka architektura nie istnieje, ale mogłaby zaimplementować interfejs API gniazd dzięki temu, że 'htonl' i' ntohl' są osobnymi funkcjami. –

+0

@SteveJessop masz rację oczywiście. Jest to prawdopodobnie * prawdziwy * powód, dla którego mamy dwie różne funkcje. http://en.wikipedia.org/wiki/Endianness#Middle-endian –

+0

@SteveJessop Tak, właśnie wymyśliłem to i próbowałem usunąć mój komentarz, ale jesteś szybki! :-). –

0

W programie kiedy piszesz int a; wiesz, że a zawiera szereg zamówioną liczbę całkowitą, program nie wie. Równie łatwo możesz podać wartość int zawierającą już wartość w porządku sieciowym. Oczywiście, jeśli użyjesz dowolnego operatora arytmetycznego na wartości, która nie jest w porządku hosta, wynik będzie niepoprawny z punktu widzenia sieci, jeśli kolejność sieci nie jest taka sama jak kolejność hosta.

Ale tak się nie dzieje, wartości uporządkowane w sieci często są utrzymywane dokładnie w ten sposób w strukturach niskiego poziomu, zanim zostaną wysłane lub tuż po ich otrzymaniu.

Co jest nie tak z programem jest to, że podczas rozmowy ntohl() swój obiecują funkcji ntohl() że int jesteś zapewniając pewne wartości zapisane w pamięci w celu sieciowego. To jest umowa. Jeśli nie jest to prawda, funkcja nie wykona tego, czego się spodziewasz, i to właśnie robisz.

Podobnie jak inne wyjaśnione na większości systemów (dużych lub małych, ale nie głupich endianów) dwie funkcje są zazwyczaj identyczne, albo odwrócenie bajtów albo no-op.

Powiązane problemy