2012-07-10 13 views
11

Ho eseguito il seguente programma su macchina little-endian [LE] [Linux, processore Intel]. Non riesco a spiegare le 3 uscite nel seguente frammento di codice. Poiché la macchina è LE, il valore di a viene memorizzato come 0x78563412. Durante la stampa, sta visualizzando il suo valore reale. Dal momento che è una macchina LE, mi aspetto che ntohl() diventi un no-op e visualizzi 0x78563412, che sta facendo. Tuttavia, mi aspetto 0x12345678 per la seconda dichiarazione di stampa contenente htonl(). Qualcuno può aiutarmi a capire perché sono uguali?Stesso output per htonl() e ntohl() su un numero intero

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

uscita:

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

risposta

23

Fin dalla sua una macchina LE, mi aspetto ntohl() essere un no-op

Questo è l'errore. L'ordine dei byte di rete è big-endian, l'ordine dei byte host è little-endian. Pertanto, sia ntohl sia htonl restituiscono una versione scambiata per byte del loro input.

Ricordate, il punto di htonl è che si può prendere un intero sull'host, quindi scrivere:

int i = htonl(a); 

e il risultato è che la memoria di i, se interpretato utilizzando l'ordine di byte di rete, ha lo stesso valore di a. Quindi, se si scrive la rappresentazione dell'oggetto di i in un socket e il lettore all'altra estremità si aspetta un intero di 4 byte in ordine di byte di rete, leggerà il valore di a.

e visualizzazione 0x78563412

E 'questo ciò che si desidera scrivere? Se ntohl fosse un no-op (o piuttosto una funzione di identità), la terza riga necessariamente stamperebbe la stessa cosa della prima linea, perché avresti ntohl(a) == a. Questo è ciò che accade su implementazioni big-endian, dove i vostri programma stampa:

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

Come @Alok menzionato di seguito, mi aspettavo che il seguente comportamento sia sempre valido: 'x == htonl (ntohl (x))'. Ma questo non sta accadendo e la tua spiegazione è stata molto utile. – Bhaskar

+2

@Bhaskar: anche il punto di Brian Roach è importante: non hai mai calcolato 'htonl (ntohl (a))'. Hai calcolato 'htonl (a)' e 'ntohl (a)'. –

+0

grazie mille! Grande spiegazione – Skully

5

Perché si sta passando a per valore e quindi non viene modificato da una di tali funzioni.

Si sta stampando cosa htonl() e ntohl() sono restituendo.

Modifica da aggiungere: Mi è mancato dove pensavi che si sarebbe un no-op. Non è. Entrambi faranno esattamente la stessa cosa su una macchina LE; invertire l'ordine dei byte. ntohl() si aspetta che tu sia di passaggio che un byte reticolo ordinato int

9

htonl e ntohl sono esattamente le stesse funzioni. Dovrebbero soddisfare htonl(ntohl(x)) == x. Sono nominati in modo diverso solo per la documentazione (rendi esplicito che stai convertendo da host-a-rete o viceversa, anche se è lo stesso).Quindi, su una macchina little-endian, entrambi eseguono lo scambio dei byte, e su una macchina big-endian, sono entrambi non operativi.

+5

Su un'ipotetica implementazione C "stupido-endian" in cui i byte non sono né big-endian (ordinato '4321') né little-endian (ordinato' 1234'), ma ordinati per esempio '3214', avresti ancora 'htonl (ntohl (x))', ma 'htonl' e' ntohl' non farebbero la stessa cosa, sarebbero rotazioni di 8 bit in direzioni opposte. Spero che questa architettura non esista, ma potrebbe implementare l'API socket grazie al fatto che 'htonl' e' ntohl' sono funzioni separate. –

+0

@SteveJessop hai ragione, naturalmente. Questo è probabilmente il motivo * reale * per cui abbiamo due funzioni diverse. http://en.wikipedia.org/wiki/Endianness#Middle-endian –

+0

@SteveJessop Sì, l'ho appena capito e stavo cercando di cancellare il mio commento, ma sei veloce! :-). –

0

Nel programma quando si scrive int a;si sanno che a contiene un host ordinata intero, il programma non sa che. Si potrebbe facilmente fornire un int che già contiene un valore nell'ordine di rete. Naturalmente se si utilizza un operatore aritmetico su un valore che non è nell'ordine host, il risultato sarà errato dal punto di vista della rete se l'ordine di rete non è lo stesso dell'ordine host.

Ma questo non è così esagerato, i valori ordinati di rete sono spesso mantenuti esattamente in quel modo in strutture di basso livello, prima di essere inviati o appena ricevuti.

Cosa c'è di sbagliato con il vostro programma è che quando si chiama il tuo ntohl() sono promettenti per la funzione ntohl() che il int si sta fornendo è un valore memorizzato nella memoria in ordine di rete. Questo è il contratto. Se non è vero, la funzione non eseguirà ciò che ti aspetti, e questo è ciò che stai vedendo.

Come altri spiegati sulla maggior parte dei sistemi (grandi o piccoli ma non stupidi-endiani) le due funzioni sono in genere identiche, sia a byte invertiti che a non-op.

Problemi correlati