75 votes

Quand l'Endiannité devient-elle un facteur ?

D'après ce que j'ai compris, on parle d'endiannité lorsque les octets qui composent un mot multi-octet diffèrent dans leur ordre, du moins dans le cas le plus typique. Ainsi, un entier de 16 bits peut être stocké sous la forme de 0xHHLL o 0xLLHH .

En supposant que je ne me trompe pas, ce que j'aimerais savoir, c'est à quel moment l'Endiane devient un facteur important lors de l'envoi d'informations entre deux ordinateurs où l'Endiane peut ou non être différent.

  • Si je transmets un entier court de 1, sous la forme d'un tableau de caractères et sans correction, est-il reçu et interprété comme 256 ?

  • Si je décompose et recompose l'entier court en utilisant le code suivant, l'endiannité ne sera-t-elle plus un facteur ?

    // 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;
    };
  • Existe-t-il un moyen standard de compenser l'endiveté ?

Merci d'avance !

55voto

Kerrek SB Points 194696

De manière très abstraite, l'endianness est une propriété de la réinterprétation d'une variable comme un tableau de caractères.

En pratique, cela importe précisément lorsque vous read() de et write() vers un flux d'octets externe (comme un fichier ou une socket). Ou encore, en parlant de manière abstraite, l'endianness importe lorsque vous sérialiser (essentiellement parce que les données sérialisées n'ont pas de système de types et sont simplement constituées d'octets idiots) ; et l'endiannité n'a pas d'incidence sur la qualité des données. pas matière sur votre langage de programmation, car le langage ne fonctionne que sur valeurs et non sur représentations . C'est en passant de l'un à l'autre que vous devez creuser les détails.

A savoir : l'écriture :

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

Ici, nous aurions pu simplement dire, reinterpret_cast<unsigned char *>(&n) et le résultat aurait dépendu de l'endiveté du système.

Et la lecture :

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

Encore une fois, ici nous aurions pu dire, uint32_t n = *reinterpret_cast<uint32_t*>(buf) et le résultat aurait dépendu de l'endiveté de la machine.

Comme vous pouvez le constater, avec les types intégraux, vous ne devez jamais connaître l'endiannité de votre propre système, mais seulement celle du flux de données, si vous utilisez des opérations algébriques d'entrée et de sortie. Avec d'autres types de données tels que double mais la question est plus compliquée.

37voto

w00te Points 11664

Pour mémoire, si vous transférez des données entre des appareils, vous devriez presque toujours utiliser l'ordonnancement par octet du réseau avec ntohl , htonl , ntohs , htons . Il sera converti à la norme d'ordre d'octet du réseau pour l'Endianness, indépendamment de ce que votre système et le système de destination utilisent. Bien sûr, les deux systèmes devraient être programmés de la sorte, mais ils le sont généralement dans les scénarios de mise en réseau.

7voto

Jerry Coffin Points 237758
  1. Non, mais vous avez la bonne idée générale. Ce qui vous échappe, c'est le fait que même s'il s'agit normalement d'une connexion série, une connexion réseau (du moins la plupart des connexions réseau) garantit toujours un endian correct au niveau de l'octet (byte) -- c'est-à-dire que si vous envoyez un byte avec une valeur de 0x12 sur une machine little endian, il sera toujours reçu comme 0x12 sur une machine big endian.

    Si vous regardez un court-circuit, si vous regardez le nombre en hexadécimal, ça vous aidera probablement. Il commence par 0x0001. Vous le cassez en deux octets : 0x00 0x01. A la réception, il sera lu comme 0x0100, qui s'avère être 256.

  2. Étant donné que le réseau traite l'endianement au niveau de l'octet, vous ne devez normalement compenser que l'ordre des octets, et non les bits dans les octets.

  3. La méthode la plus simple consiste probablement à utiliser htons/htonl pour l'envoi et ntohs/ntohl pour la réception. Si cela ne suffit pas, il existe de nombreuses alternatives telles que XDR, ASN.1, CORBA IIOP, les tampons de protocole de Google, etc.

6voto

Ray Toal Points 35382

La "manière standard" de compenser est que le concept d'"ordre des octets du réseau" a été défini, presque toujours (AFAIK) comme big endian.

Les émetteurs et les récepteurs connaissent tous deux le protocole filaire et, si nécessaire, ils le convertissent avant la transmission et après la réception, afin de fournir aux applications les bonnes données. Mais cette traduction se fait dans votre couche réseau mais pas dans vos applications.

6voto

amoss Points 445

Les deux endianesses ont un avantage que je connais :

  1. Le système Big-endian est conceptuellement plus facile à comprendre car il est similaire à notre système de numération positionnelle : du plus significatif au moins significatif.
  2. Little-endian est pratique lorsqu'on réutilise une référence mémoire pour plusieurs tailles de mémoire. En d'autres termes, si vous avez un pointeur sur un fichier little-endian unsigned int* mais vous savez que la valeur stockée est < 256, vous pouvez convertir votre pointeur en unsigned char* .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X