tutorial smart remix español curso aprender c++ networking stl endianness

c++ - smart - ¿Cuándo se convierte Endianness en un factor?



solidity español (8)

Endianness de lo que entiendo, es cuando los bytes que componen una palabra multibyte difieren en su orden, al menos en el caso más típico. De modo que un entero de 16 bits puede almacenarse como 0xHHLL o 0xLLHH .

Suponiendo que no me equivoque, lo que me gustaría saber es cuándo Endianness se convierte en un factor importante cuando se envía información entre dos computadoras donde Endian puede o no ser diferente.

  • Si transmito un entero corto de 1, en forma de una matriz de caracteres y sin corrección, ¿se recibe e interpreta como 256?

  • Si descompongo y recompongo el entero corto usando el siguiente código, ¿la endianidad ya no será un factor?

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

  • ¿Hay una forma estándar de compensar el endianismo?

¡Gracias por adelantado!


  1. No, aunque tienes la idea general correcta. Lo que te falta es el hecho de que a pesar de que normalmente es una conexión en serie, una conexión de red (al menos la mayoría de las conexiones de red) aún garantiza la correcta endianidad en el nivel del octeto (byte), es decir, si envías un byte con un valor de 0x12 en una pequeña máquina endian, todavía se recibirá como 0x12 en una máquina endian grande.

    Mirando un resumen, si miras el número en hexadecimal, probablemente te ayude. Comienza como 0x0001. Lo divide en dos bytes: 0x00 0x01. Al recibirlo, se leerá como 0x0100, que resulta ser 256.

  2. Dado que la red se ocupa de endianess en el nivel del octeto, normalmente solo tiene que compensar el orden de los bytes, no los bits dentro de los bytes.

  3. Probablemente el método más simple es usar htons / htonl al enviar, y ntohs / ntohl al recibir. Cuando / si eso no es suficiente, hay muchas alternativas como XDR, ASN.1, CORBA IIOP, buffers de protocolo de Google, etc.


Ambas endianeos tienen una ventaja que yo conozco:

  1. Big-endian es conceptualmente más fácil de entender porque es similar a nuestro sistema de numeración posicional: de más significativo a menos significativo.
  2. Little-endian es conveniente cuando se reutiliza una referencia de memoria para múltiples tamaños de memoria. En pocas palabras, si tiene un puntero a una unsigned int* little-endian pero sabe que el valor almacenado allí es <256, puede convertir su puntero a unsigned char* .

Aquí hay algunas pautas para C / C ++ endian-neutral code. Obviamente, estos están escritos como "reglas para evitar" ... así que si el código tiene estas "características" podría ser propenso a errores relacionados con endian !! (Esto es de mi artículo sobre Endianness publicado en Dr Dobbs)

  1. Evite utilizar uniones que combinen diferentes tipos de datos de múltiples bytes. (el diseño de los sindicatos puede tener diferentes órdenes relacionadas con endian)

  2. Evite acceder a matrices de bytes fuera del tipo de datos de bytes. (el orden de la matriz de bytes tiene un orden relacionado con Endian)

  3. Evite el uso de campos de bits y máscaras de bytes (dado que el diseño del almacenamiento depende de la endianidad, el enmascaramiento de los bytes y la selección de los campos de bits es sensible a endian)

  4. Evite enviar punteros del tipo de varios bytes a otros tipos de bytes.
    (cuando se lanza un puntero de un tipo a otro, la endianidad de la fuente (es decir, el objetivo original) se pierde y el procesamiento posterior puede ser incorrecto)


En términos muy abstractos, endianness es una propiedad de la reinterpretación de una variable como una matriz char.

Prácticamente, esto importa precisamente cuando read() desde y write() en una secuencia de bytes externa (como un archivo o un socket). O, hablando en abstracto de nuevo, la endiosidad es importante cuando serializa los datos (esencialmente porque los datos serializados no tienen un sistema de tipo y solo constan de bytes tontos); y endianness no importa dentro de su lenguaje de programación, porque el lenguaje solo opera en valores , no en representaciones . Para ir de uno a otro es necesario profundizar en los detalles.

A saber, escribir:

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

Aquí podríamos haber dicho, reinterpret_cast<unsigned char *>(&n) , y el resultado habría dependido de la endianidad del sistema.

Y leyendo:

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

De nuevo, aquí podríamos haber dicho, uint32_t n = *reinterpret_cast<uint32_t*>(buf) , y el resultado habría dependido del endianness de la máquina.


Como puede ver, con los tipos integrales, nunca debe conocer la endianidad de su propio sistema, solo de la secuencia de datos, si utiliza operaciones de entrada y salida algebraicas. Con otros tipos de datos como el double , el problema es más complicado.


Endianidad SIEMPRE es un problema. Algunos dirán que si sabes que cada host conectado a la red ejecuta el mismo sistema operativo, etc., entonces no tendrás problemas. Esto es cierto hasta que no lo es. Siempre debe publicar una especificación que detalle el formato EXACTO de los datos en el cable. Puede ser cualquier formato que desee, pero cada punto final necesita comprender el formato y ser capaz de interpretarlo correctamente.

En general, los protocolos usan big-endian para valores numéricos, pero esto tiene limitaciones si no todos son compatibles con IEEE 754, etc. Si puede tomar los gastos generales, use un XDR (o su solución favorita) y esté seguro.


La "forma estándar" de compensar es que el concepto de "orden de bytes de red" se ha definido, casi siempre (AFAIK) como big endian.

Los remitentes y los receptores conocen el protocolo de cableado y, si es necesario, lo convierten antes de transmitir y después de recibirlo, para dar a las aplicaciones los datos correctos. Pero esta traducción ocurre dentro de su capa de red , no en sus aplicaciones.


No deberías preocuparte, a menos que estés en el límite del sistema. Normalmente, si estás hablando en términos del stl, ya pasaste ese borde.

La tarea del protocolo de serialización es indicar / determinar cómo se puede transformar una serie de bytes en el tipo que está enviando, ya sea un tipo integrado o un tipo personalizado.

Si solo está hablando integrado, puede ser suficiente con la abstracción de la máquina proporcionada por las herramientas provistas por su entorno ]


Para el registro, si está transfiriendo datos entre dispositivos, casi siempre debe usar el orden de bytes de red con ntohl , htonl , ntohs , htons . Se convertirá al estándar de orden de bytes de red para Endianness independientemente de lo que usen su sistema y el sistema de destino. Por supuesto, ambos sistemas deberían programarse de esta manera, pero generalmente están en escenarios de red.