web-dev-qa-db-fra.com

C # petit endian ou big endian?

Dans la documentation du matériel qui nous permet de le contrôler via UDP/IP, J'ai trouvé le fragment suivant:

Dans ce protocole de communication, DWORD est une donnée de 4 octets, Word est une donnée de 2 octets, BYTE est une donnée à un octet. Le format de stockage est peu important, à savoir 4 octets (32bits). Les données sont stockées comme suit: d7-d0, d15-d8, d23-d16, d31-d24; les données sur deux octets (16 bits) sont stockées comme suit: d7-d0, d15-d8.

Je me demande comment cela se traduit en C #? Dois-je convertir des éléments avant de les envoyer? Par exemple, si je veux envoyer un entier 32 bits ou une chaîne de 4 caractères?

55
TimothyP

C # lui-même ne définit pas la finalité. Cependant, chaque fois que vous convertissez en octets, vous faites un choix. La classe BitConverter a un champ IsLittleEndian pour vous dire comment elle se comportera, mais cela ne donne pas le choix. La même chose vaut pour BinaryReader/BinaryWriter.

My MiscUtil library a une classe EndianBitConverter qui vous permet de définir l’endianness; il existe des équivalents similaires pour BinaryReader/Writer. Je crains qu'il n'y ait pas de guide d'utilisation en ligne, mais ils sont triviaux :)

(EndianBitConverter a également une fonctionnalité qui n’est pas présente dans BitConverter normal, qui consiste à effectuer des conversions sur place dans un tableau d’octets.)

74
Jon Skeet

Vous pouvez aussi utiliser

IPAddress.NetworkToHostOrder(...)

Pour court, int ou long.

43
Jan Bannister

En ce qui concerne little-endian, la réponse courte (pour faire, je dois tout faire) est "probablement pas, mais cela dépend de votre matériel". Vous pouvez vérifier avec:

bool le = BitConverter.IsLittleEndian;

En fonction de ce que cela dit, vous voudrez peut-être inverser des parties de vos tampons. Alternativement, Jon Skeet a des convertisseurs Endian spécifiques ici (recherchez EndianBitConverter).

Notez que les itaniums (par exemple) sont big-endian. La plupart des Intels sont little-endian.

Concernant le protocole UDP/IP spécifique?

10
Marc Gravell

Vous devez connaître l’ordre des octets du réseau ainsi que l’endian-ness du processeur.

Généralement, pour les communications TCP/UDP, vous convertissez toujours les données en ordre d'octet réseau à l'aide de la fonction htons (et ntohs, ainsi que des fonctions associées).

Normalement, l'ordre du réseau est big-endian, mais dans ce cas (pour une raison quelconque!), Les communications sont peu endianes, donc ces fonctions ne sont pas très utiles. Ceci est important car vous ne pouvez pas supposer que les communications UDP qu’ils ont implémentées sont conformes à d’autres normes. Cela rend également la vie difficile si vous avez une architecture big-endian, car vous ne pouvez pas tout encapsuler avec htons comme vous devriez:

Cependant, si vous venez d'une architecture Intel x86, vous êtes déjà un peu endianiste, alors envoyez simplement les données sans conversion.

3
gbjbaanb

Je joue avec des données compactes dans UDP Multicast et j'avais besoin de quelque chose pour réorganiser les octets UInt16 car j'avais remarqué une erreur dans l'en-tête du paquet (Wireshark), alors j'ai fait ceci:

    private UInt16 swapOctetsUInt16(UInt16 toSwap)
    {
        Int32 tmp = 0;
        tmp = toSwap >> 8;
        tmp = tmp | ((toSwap & 0xff) << 8);
        return (UInt16) tmp;
    }

Dans le cas de UInt32,

    private UInt32 swapOctetsUInt32(UInt32 toSwap)
    {
        UInt32 tmp = 0;
        tmp = toSwap >> 24;
        tmp = tmp | ((toSwap & 0xff0000) >> 8);
        tmp = tmp | ((toSwap & 0xff00) << 8);
        tmp = tmp | ((toSwap & 0xff) << 24);
        return tmp;
    }

Ceci est juste pour tester

    private void testSwap() {
        UInt16 tmp1 = 0x0a0b;
        UInt32 tmp2 = 0x0a0b0c0d;
        SoapHexBinary shb1 = new SoapHexBinary(BitConverter.GetBytes(tmp1));
        SoapHexBinary shb2 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt16(tmp1)));
        Debug.WriteLine("{0}", shb1.ToString());
        Debug.WriteLine("{0}", shb2.ToString());
        SoapHexBinary shb3 = new SoapHexBinary(BitConverter.GetBytes(tmp2));
        SoapHexBinary shb4 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt32(tmp2)));
        Debug.WriteLine("{0}", shb3.ToString());
        Debug.WriteLine("{0}", shb4.ToString());
    }

à partir de quelle sortie était-ce:

    0B0A: {0}
    0A0B: {0}
    0D0C0B0A: {0}
    0A0B0C0D: {0}
0
Marko Samirić

Si vous analysez et que les performances ne sont pas critiques, considérez ce code très simple:

private static byte[] NetworkToHostOrder (byte[] array, int offset, int length)
{
    return array.Skip (offset).Take (length).Reverse ().ToArray ();
}

int foo = BitConverter.ToInt64 (NetworkToHostOrder (queue, 14, 8), 0);
0
mafu