web-dev-qa-db-fra.com

Tableau d'int à octets

Je pensais que .net avait une sorte de méthode de conversion facile à utiliser pour convertir un int en un tableau d'octets? J'ai fait une recherche rapide et toutes les solutions masquent/décalent les bits un octet à la fois, comme "les bons vieux jours". N'y a-t-il pas quelque part une méthode ToByteArray ()?

54
Brady Moritz
byte[] bytes = BitConverter.GetBytes(i);

notez cependant que vous pourriez voulez vérifier BitConverter.IsLittleEndian pour voir dans quel sens cela va apparaître!

Notez que si vous faites cela à plusieurs reprises vous voudrez peut-être éviter toutes ces allocations de tableaux de courte durée en l'écrivant vous-même via l'une ou l'autre des opérations de décalage (>>/<<), ou en utilisant le code unsafe. Les opérations de décalage également ont l'avantage de ne pas être affectées par l'endianité de votre plateforme; vous toujours obtenez les octets dans l'ordre dans lequel vous les attendez.

89
Marc Gravell

La réponse de Marc est bien sûr la bonne réponse. Mais comme il a mentionné les opérateurs de décalage et le code dangereux comme alternative. Je voudrais partager une alternative moins courante. Utilisation d'une structure avec une disposition Explicit. Ceci est similaire en principe à un C/C++ union.

Voici un exemple de structure qui peut être utilisée pour accéder aux octets de composants du type de données Int32 et ce qui est bien, c'est que c'est bidirectionnel, vous pouvez manipuler les valeurs d'octets et voir l'effet sur l'Int.

  using System.Runtime.InteropServices;

  [StructLayout(LayoutKind.Explicit)]
  struct Int32Converter
  {
    [FieldOffset(0)] public int Value;
    [FieldOffset(0)] public byte Byte1;
    [FieldOffset(1)] public byte Byte2;
    [FieldOffset(2)] public byte Byte3;
    [FieldOffset(3)] public byte Byte4;

    public Int32Converter(int value)
    {
      Byte1 = Byte2 = Byte3 = Byte4 = 0;
      Value = value;
    }

    public static implicit operator Int32(Int32Converter value)
    {
      return value.Value;
    }

    public static implicit operator Int32Converter(int value)
    {
      return new Int32Converter(value);
    }
  }

Ce qui précède peut maintenant être utilisé comme suit

 Int32Converter i32 = 256;
 Console.WriteLine(i32.Byte1);
 Console.WriteLine(i32.Byte2);
 Console.WriteLine(i32.Byte3);
 Console.WriteLine(i32.Byte4);

 i32.Byte2 = 2;
 Console.WriteLine(i32.Value);

Bien sûr, la police d'immuabilité peut ne pas être enthousiasmée par la dernière possibilité :)

30
Chris Taylor

Cela peut être OT mais si vous sérialisez beaucoup de types primitifs ou de structures POD, Google Protocol Buffers for .Net pourrait vous être utile. Cela résout l'endianness problème @Marc soulevé ci-dessus, entre autres fonctionnalités utiles.

2
Steve Townsend

Si vous êtes venu ici de Google

Une réponse alternative à une question plus ancienne fait référence à la bibliothèque de John Skeet qui a des outils pour vous permettre d'écrire des types de données primitifs directement dans un octet [] avec un décalage d'index. Bien mieux que BitConverter si vous avez besoin de performances.

Ancien fil traitant de ce problème ici

Les bibliothèques de John Skeet sont ici

Téléchargez simplement la source et regardez le MiscUtil.Conversion espace de noms. EndianBitConverter.cs s'occupe de tout pour vous.

1
JamesHoux

La plupart des réponses ici sont "non sécurisées" ou non sécurisées par LittleEndian. BitConverter n'est pas sûr par LittleEndian. Donc, en me basant sur un exemple en ici (voir l'article de PZahra), j'ai fait une version sûre de LittleEndian simplement en lire le tableau d'octets à l'envers lorsque BitConverter.IsLittleEndian == true

void Main(){    
    Console.WriteLine(BitConverter.IsLittleEndian); 
    byte[] bytes = BitConverter.GetBytes(0xdcbaabcdfffe1608);
    //Console.WriteLine(bytes); 
    string hexStr = ByteArrayToHex(bytes);
    Console.WriteLine(hexStr);
}

public static string ByteArrayToHex(byte[] data) 
{ 
   char[] c = new char[data.Length * 2]; 
   byte b; 
  if(BitConverter.IsLittleEndian)
  {
        //read the byte array in reverse
        for (int y = data.Length -1, x = 0; y >= 0; --y, ++x) 
        { 
            b = ((byte)(data[y] >> 4)); 
            c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
            b = ((byte)(data[y] & 0xF)); 
            c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
        }               
    }
    else
    {
        for (int y = 0, x = 0; y < data.Length; ++y, ++x) 
        { 
            b = ((byte)(data[y] >> 4)); 
            c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
            b = ((byte)(data[y] & 0xF)); 
            c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
        }
    }
    return String.Concat("0x",new string(c));
}

Il renvoie ceci:

True
0xDCBAABCDFFFE1608

qui est l'hex exact qui est entré dans le tableau d'octets.

0
GregJF