2012-07-10 10 views
11

Ejecuté el siguiente programa en la máquina little-endian [LE] [Linux, procesador Intel]. No puedo explicar las 3 salidas en el siguiente fragmento de código. Como la máquina es LE, el valor de a se almacena como 0x78563412. Al imprimir, muestra su valor real. Como se trata de una máquina LE, espero que ntohl() no funcione y muestre 0x78563412, lo que está haciendo. Sin embargo, espero 0x12345678 para la segunda declaración de impresión que contiene htonl(). ¿Alguien puede ayudarme a entender por qué son lo mismo?Mismo resultado para htonl() y ntohl() en un entero

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

Salida:

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

Respuesta

23

Desde su una máquina LE, espero ntohl() ser un no-op

Ese es el error. El orden de bytes de la red es big-endian, la orden del byte del host es little-endian. Por lo tanto, tanto ntohl como htonl devuelven una versión intercambiada por bytes de su entrada.

Recuerde, el punto de htonl es que se puede tomar un número entero en el host, a continuación, escribir:

int i = htonl(a); 

y el resultado es que la memoria de i, si se interpreta usando el orden de bytes de red, tiene el mismo valor que a. Por lo tanto, si escribe la representación de objeto de i en un socket y el lector en el otro extremo espera un entero de 4 bytes en orden de bytes de red, leerá el valor de a.

y visualización 0x78563412

¿Es esto lo que trataba de escribir? Si ntohl fuera una operación (o más bien, una función de identidad), entonces su tercera línea necesariamente imprimiría lo mismo que su primera línea, porque tendría ntohl(a) == a. Esto es lo que sucede en las implementaciones big-endian, donde las impresiones del programa:

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

Como @Alok mencionan a continuación, que estaba esperando el siguiente comportamiento siempre será verdad: 'x == htonl (ntohl (x))'. Pero esto no está sucediendo y tu explicación fue muy útil. – Bhaskar

+2

@Bhaskar: punto de Brian Roach también es importante, entonces: nunca se ha calculado 'htonl (ntohl (a))'. Calculó 'htonl (a)' y 'ntohl (a)'. –

+0

muchas gracias! Gran explicación – Skully

5

Debido a que estás pasando a por su valor y por lo tanto no se cambia por cualquiera de esas funciones.

Está imprimiendo lo que htonl() y ntohl() son que devuelven.

Editar para agregar: Echaba de menos donde creía que sería una falta de oportunidades. No es. Ambos van a hacer exactamente lo mismo en una máquina LE; revertir el orden de bytes. ntohl() está esperando que usted sea de paso es un byte de red ordenada int

9

htonl y ntohl son exactamente las mismas funciones. Se supone que satisfacen htonl(ntohl(x)) == x. Se nombran de manera diferente solo para la documentación (usted hace explícito que está convirtiendo de host a red o de otra manera, incluso si es el mismo).Por lo tanto, en una máquina little-endian, ambos realizan el intercambio de bytes, y en una máquina de big-endian, ambos son no-ops.

+5

En un hipotético "estúpida-endian" aplicación C, donde los bytes son ni big-endian (ordenados '4321'), ni ascendente hacia la izquierda (ordenados' 1234'), pero ordenada, por ejemplo, '3214', todavía tendría 'htonl (ntohl (x))', pero 'htonl' y' ntohl' no harían lo mismo, serían rotaciones de 8 bits en direcciones opuestas. Espero que no exista tal arquitectura, pero podría implementar la API de sockets gracias al hecho de que 'htonl' y' ntohl' son funciones separadas. –

+0

@SteveJessop tienes razón, por supuesto. Esta es probablemente la razón * real * por la que tenemos dos funciones diferentes. http://en.wikipedia.org/wiki/Endianness#Middle-endian –

+0

@SteveJessop Sí, acabo de cuenta de eso y estaba tratando de borrar mi comentario, pero usted es rápido! :-). –

0

En su programa cuando se escribe int a;que saben que a contiene una serie ordenada de enteros, el programa no sabe que. También podría proporcionar una int que ya contenga un valor en el orden de la red. Por supuesto, si utiliza un operador aritmético en un valor que no está en el orden del host, el resultado será incorrecto desde el punto de vista de la red si el orden de la red no es el mismo que el orden del host.

Pero esto no es tan descabellada, la red ordenaron los valores se mantienen a menudo exactamente de esa manera en las estructuras de bajo nivel, antes de ser enviado o simplemente después de haber sido recibido.

Lo que está mal con su programa es que cuando se llama a su ntohl() están prometiendo a la función ntohl() que el int que está proporcionando algo de valor almacenado en la memoria con el fin de red. Ese es el contrato. Si no es así, la función no funcionará como esperabas, y eso es lo que estás viendo.

Como otra explicado en la mayoría de los sistemas (grandes o pequeños, pero no estúpidos-endians) las dos funciones son generalmente idénticos, ya sea un bytes inversa o un no-op.

Cuestiones relacionadas