Frage c #: Konvertiere ein int in das kleinste Byte-Array, in das es passt


Ich hätte gerne eine elegante, effiziente Möglichkeit, jede vorzeichenlose Ganzzahl zu nehmen und sie in das kleinste Bytearray umzuwandeln, in das sie hineinpasst. Beispielsweise:

250 = byte[1]
2000 = byte[2]
80000 = byte[3]

damit ich schreiben kann:

var foo = getBytes(bar);

und foo wird je nach Wert von verschiedenen Längen sein bar. Wie würde ich das tun?


7
2017-11-07 14:19


Ursprung


Antworten:


Sie können es so tun, als eine Erweiterungsmethode:

public static byte[] ToByteArray(this int value) {
     var bytes = Enumerable
                     .Range(0, sizeof(int))
                     .Select(index => index * 8)
                     .Select(shift => (byte)((value >> shift) & 0x000000ff))
                     .Reverse()
                     .SkipWhile(b => b == 0x00)
                     .ToArray();
     return bytes;
}

Dann:

int j = 2000;
var bytes = j.ToByteArray();
Console.WriteLine(bytes.Length);
for(int index = 0; index < bytes.Length; index++) {
    Console.WriteLine("{0:x}", bytes[index]);
}

Gibt:

2
0x07
0xd0

Und ersetzen j = 2000 durch j = 80000 im obigen gibt

3
0x01
0x38
0x80

Und ersetzen j = 2000 durch j = 250 im obigen gibt

1
0xfa

3
2017-11-07 14:29



Es gibt keine einzige Methode, die Sie verwenden können, aber Sie können es leicht tun (Warnung - nicht getestet)

byte[] bytes;

if ((i & 0xffffff00)==0) {
    bytes = new byte[] { (byte)i };
}
else if ((i & 0xffff0000)==0) {
    bytes = new byte[] { (byte)(i & 0xff), (byte)((i & 0xff00) >> 8) };
}
else if ((i & 0xff000000)==0) {
    bytes = new byte[] { (byte)(i & 0xff), (byte)((i & 0xff00) >> 8), (byte)((i & 0xff0000) >> 16) };
}
else {
    bytes = BitConverter.GetBytes(i);
}

2
2017-11-07 14:26



Dadurch erhalten Sie alle Bytes:

static byte[] GetBytes(uint bar)
    {
        return BitConverter.GetBytes(bar).Reverse().SkipWhile(c => c == 0).Reverse().ToArray();
    }

2
2017-11-07 14:41



Sie können die Grenzpunkte wahrscheinlich nur hart codieren, aber wenn Sie einen dynamischeren Ansatz wünschen, könnten Sie etwas wie folgt verwenden:

byte[] getBytes(uint bar) {
    if (bar == 0) return new byte[0];

    return getBytes(bar / 256)
            .Concat(Enumerable.Repeat((byte)(bar % 256), 1))
            .ToArray();
}

1
2017-11-07 14:28



Es ist auch für den langen Typ geeignet (die einzige Änderung ist "Byte? [4]" bis "Byte? [8]" und natürlich die Deklaration).

static byte[] ToArray(int num) 
{
    byte?[] b = new byte?[4];
    int i = 0;

    do b[i++] = (byte)num;
    while ((num = num >> 8) > 0);

    byte[] result = new byte[i];
    for (int j = 0; j < i; j++)
        result[j] = b[j].Value;

    return result;
}

1
2017-11-07 14:57



private byte[] GetBytes(int number)
{            
    if (number < 0) 
    {
        throw new ArgumentException("Can not be less than zero", "number");
    }

    int numberOfBits = 0;
    while (number > 0)
    {
        numberOfBits++;
        number = number >> 1;
    }

    int reminder = 0;
    int numberofBytes = Math.DivRem(numberOfBits, 8, out reminder);
    numberofBytes = reminder > 0 ? numberofBytes + 1 : numberofBytes;
    return new byte[numberofBytes];
}

0
2017-11-07 14:37



Dies sollte ziemlich schnell sein und es weist nur genau so viel Platz zu, wie es benötigt wird.

static byte[] getBytes(long a)
{
    int k=0;
    for (long b=a; b!=0; b>>=8) k++;
    byte[] res = new byte[k];
    for (k=0; a!=0; a>>=8)
        res[res.Length-(++k)] = (byte)(a&0xFF);
    return res;
}

0
2017-11-07 14:47