Объединение 17-битных данных в байтовый массив

#c #bytearray #bit-manipulation

#c #массивы #манипулирование битами

Вопрос:

У меня возникла небольшая проблема при попытке переместить группы из 17-битных данных в байтовый массив. Я не хочу проходить пошагово, но я не могу разобраться в логическом цикле.
Мне это нужно таким образом, потому что я должен вычислять контрольную сумму путем сложения всех байтовых значений после их объединения таким образом.
Итак, вот с чем я борюсь.

У меня есть 16-байтовые массивы. Первые 3 байта массива содержат 17 бит, которые мне нужны. (8 бит из [0] , 8 бит из [1] и MSB из [2] .)

Мне нужно переместить эти 16 17-битных значений в один отдельный байтовый массив.

Первый из них прост:

 int index = 0;
myArray[index  ] = driverData[driver][0];            //First byte
myArray[index  ] = driverData[driver][1];            //Second byte
myArray[index] = (driverData[driver][2] amp; 0x80) << 7;  //First bit of the third byte.
  

Отсюда, однако, становится все труднее пытаться выполнить какой-либо цикл для их перемещения.

 driver  ;<br>
//Take the 7 MSBs from the data array.
myArray[index  ] |= (byte)(driverData[driver][0] amp; 0x7e >> 1);
//This leaves a single bit left over on driverData[driver][0].
myArray[index] = (byte)(driverData[driver][1] amp; 0x1 << 7);
  

Я думаю, вы поняли картину. Я все это делаю неправильно? Кто-нибудь может указать мне правильное направление?

Комментарии:

1. (надеюсь, я не слишком сильно испортил вашу текущую правку, извините 🙂 Я думаю, что на самом деле это может быть проще с driverData[driver][1] конструкцией, чем с data1 конструкцией data2 , driver , поскольку затем вы также можете выполнить итерацию по, а также. (Также обратите внимание, что в описании говорится [1] , [2] [3] , [0] , но в коде говорится [1] , [3] ,,,.)

2. Нет, вы его значительно улучшили, спасибо. Я быстро исправлю эти проблемы. Спасибо.

3. сарнольд… Я понятия не имею, как вы его отформатировали с выделенным кодом и т.д… Думаю, я только что уничтожил ваши превосходные правки.

4. Итак, просто для ясности, первые три байта каждого входного массива содержат 17 бит информации. И вы должны упаковать эти группы из 17 бит последовательно в байтовый массив? Итак, 1-й байт выходных данных содержит 1-е 8 бит 1-го массива, 2-й байт выходных данных содержит 2-е 8 бит 1-го массива, 3-й байт выходных данных содержит последний бит 1-го массива и 1-е 7 бит 2-го массива и так далее?

5. Да, квантовая механика. Это точно.

Ответ №1:

Похоже, у вас цикл с простыми числами, достаточно большой, чтобы сделать кодирование отдельных случаев плохой идеей. Это классическая проблема упаковки. Вам нужен цикл, который повторяет ваш пункт назначения, и некоторый внутренний код, который получает больше битов для упаковки. Ваш упаковочный код должен знать, сколько битов доступно для него с последней итерации, сколько ему нужно, и должен иметь возможность увеличивать указатель источника, если его недостаточно.

Комментарии:

1. Хорошо, итак, как бы вы это кодировали?

2. @Spenduku: будет проще, если вы будете делать это по одному биту за раз. Удалите 17 бит из очереди ввода, поставьте в очередь 17 бит на выходе. Обе стороны должны отслеживать текущий байт и текущий бит внутри этого байта.

3. Я должен поблагодарить вас, bk1e, поскольку ваш комментарий, казалось, подсказал, как этого добиться.

Ответ №2:

Хорошо, похоже, это работает. Вероятно, мне нужно протестировать это еще раз, но, похоже, это дает мне результат, которого я пока ожидаю. Я уверен, что мог бы сделать это как-то лучше.

 // ... //
void foo()
{
    //Lets start by getting all the 17bit values from each driver for the board.
    int bitIndex = 7;
    int byteIndex = 0;
    int stopIndex = chipIndex   GetChipCount();
    //Now we start the shiftyness.
    for (int driver = chipIndex; driver < stopIndex; driver  ) {
        int userBits =
            (driverData[driver][0] amp; 0xff) << 9 | (driverData[driver][1]
                               amp; 0xff)
            << 1 | (driverData[driver][2] amp; 0x80) >> 7;
        AddBitsToArray(userBits, ref bitIndex, ref byteIndex);

    }
}

/// <summary>
/// Takes the 17 bits, and adds them to the byte array.
/// </summary>
private void AddBitsToArray(int userBits, ref int bitIndex, ref int byteIndex)
{
    int bitCount = 17;
    while (bitCount > 0) {
        //First 8 bytes.
        checksumBytes[byteIndex] |=
            (byte) (((userBits amp; bitValue(bitCount - 1)) >>
                 (bitCount - 1)) << bitIndex);
        //Move up the bit index to be written to.
        bitIndex--;
        //Decrement the number of bits left to shift.
        bitCount--;
        //If we have gone past the 8th bit, reset the bitIndex and increment the byteIndex.
        if (bitIndex >= 0)
            continue;
        bitIndex = 7;
        byteIndex  ;
    }
}

/// <summary>
/// Returns the value of a single bit at the given index.
/// </summary>
private int bitValue(int bitIndex)
{
    return (int)(Math.Pow(2, bitIndex));
}
  

Комментарии:

1. Это чище, чем все, что я придумал 🙂 если он пройдет ваши тесты, я бы сказал, будьте довольны этим. 🙂

2. Хорошо, будет сделано. Спасибо за вашу помощь в редактировании, сарнольд. 🙂 Похоже, что код JYeltons тоже отлично работает, жаль, что я не могу выбрать два ответа

Ответ №3:

Вот что я придумал. Первая часть метода — это просто настройка некоторых поддельных входных данных, поэтому удалите это и добавьте аргументы по мере необходимости. OutputData Массив излишне большой, но я не тратил время на вычисление его фактической длины.

Я использовал 170 в качестве входного значения, которое является 10101010 и было полезно при проверке.

 private void BitShift17()
{
    const int NumChunks = 16;
    byte[] DriverData = new byte[]
        {
            170,
            170,
            170
        };
    byte[][] InputData = new byte[NumChunks][];
    for (int n = 0; n < NumChunks; n  )
        InputData[n] = DriverData;

    byte[] OutputData = new byte[NumChunks * 3]; // Unnecessarily large

    int OutputIndex = 0;
    int BitPosition = 0;
    for (int Driver = 0; Driver < InputData.Length; Driver  )
    {
        for (int InputIndex = 0; InputIndex < 3; InputIndex  )
        {
            byte InputByte = InputIndex == 2 ? (byte)(InputData[Driver][InputIndex] amp; 128) : InputData[Driver][InputIndex];
            if (BitPosition == 0)
            {
                OutputData[OutputIndex] = InputByte;
                if (InputIndex == 2)
                    BitPosition  ;
                else
                    OutputIndex  ;
            }
            else
            {
                if (InputIndex == 2)
                {
                    OutputData[OutputIndex] |= (byte)(InputByte >> BitPosition);
                    BitPosition  ;
                }
                else
                {
                    OutputData[OutputIndex] |= (byte)(InputByte >> BitPosition);
                    OutputIndex  ;
                    OutputData[OutputIndex] = (byte)(InputByte << 8 - BitPosition);
                }
            }
        }
        if (BitPosition > 7) BitPosition = 0;
    }
}
  

Комментарии:

1. Хммм… Я тоже проверю это и посмотрю, что у меня получится. На мгновение слишком поздно! 🙂 Спасибо Джелтону.

2. Я пометил ваш ответ как правильный, поскольку вы тоже приложили усилия. Еще раз спасибо.