c #: преобразовать int в наименьший байтовый массив, в который он поместится - PullRequest
7 голосов
/ 07 ноября 2011

Мне бы хотелось изящное, эффективное средство для взятия любого целого без знака и преобразования его в наименьший байтовый массив, в который он поместится.Например:

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

, чтобы я мог написать:

var foo = getBytes(bar);

и foo будут разной длины в зависимости от значения bar.Как бы я это сделал?

Ответы [ 7 ]

3 голосов
/ 07 ноября 2011

Вы можете сделать это так, как метод расширения:

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

Тогда:

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

Дает:

2
0x07
0xd0

И заменить j = 2000 на j = 80000 в приведенном выше дает

3
0x01
0x38
0x80

И замена j = 2000 на j = 250 в приведенном выше дает

1
0xfa
2 голосов
/ 07 ноября 2011

Это даст вам все байты:

static byte[] GetBytes(uint bar)
    {
        return BitConverter.GetBytes(bar).Reverse().SkipWhile(c => c == 0).Reverse().ToArray();
    }
2 голосов
/ 07 ноября 2011

Нет единственного метода, который вы можете использовать, но вы можете сделать это довольно легко (предупреждение - не проверено)

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);
}
1 голос
/ 07 ноября 2011

Это также подходит для длинного типа (единственное изменение - «byte? [4]» на «byte? [8]» и, конечно, объявление).

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 голос
/ 07 ноября 2011

Возможно, вы просто жестко закодируете граничные точки, но если вы хотите более динамичный подход, вы можете использовать что-то вроде этого:

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

    return getBytes(bar / 256)
            .Concat(Enumerable.Repeat((byte)(bar % 256), 1))
            .ToArray();
}
0 голосов
/ 07 ноября 2011

Это должно быть достаточно быстро, и оно выделяет ровно столько места, сколько нужно.

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 голосов
/ 07 ноября 2011
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];
}
...