Little Big Endian Бит Операция и извлечение

0

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

Ну, бит-поток хранится как массив байтов в 32-битном Micro. Но поток немногочисленный, например, поток байтов ниже

LSBit (бит 0) → 0100 1001 0100 0100 <- MSBit (бит 15)

сохраняется в памяти как

Байт 0 1001 0010 Бит, бит 7-> 1001 0010 → Бит 0

Байт 1 0010 0010 Бит, бит 15-> 0010 0010 → Бит 8

здесь битовая компоновка в байте - Big Endian, но байты Little Endian.

Если мне нужно извлечь бит 4 в 11 из потока Little endian, чтобы получить 0010 1001, тогда мне нужно извлечь

от байт 0

1001, Более высокий кусок байта 0

от байта 1

0010, нижний кусок байта 1

Сдвиньте биты слева от байта 1, чтобы получить 0010 и OR с 1001 из байт 0

Проблема состоит в том, что поток может идти до 64 бит, а число бит (до 64) является произвольным, а начальный бит произвольным. Но для хранения внутри я могу, конечно, хранить в соответствующем типе данных, который может, конечно, соответствовать бит.

И чтобы добавить к этому, я должен упаковать их таким же образом, от действительных данных в этот поток Little Big Endian. : '(

Мне также нужно беспокоиться о времени выполнения, а также о том, что он длится 4 байта. Поэтому для хранения значения 48 бит мне нужно поддерживать массив из 6 байтов, расположенных в формате хоста. без long long поддержки компилятора.

EDIT: поддерживается 64-битная long long поддержка; Я просто проверил руководство к компилятору.

Любые предложения, пожалуйста, я застрял уже три недели.

  • 0
    Добро пожаловать в стек переполнения. Пожалуйста, прочитайте страницу О скоро. Правильно ли я вас понимаю, что у вас есть входящий поток байтов в порядке с прямым порядком байтов, и этот поток байтов может иметь длину до 8 байтов. Из этого потока вы должны выбрать произвольный набор битов и сохранить их в 64-битное целое число (поскольку может быть запрошено до 64 бит)?
  • 0
    Это похоже на домашнюю работу ...
Показать ещё 13 комментариев
Теги:
bitarray

2 ответа

2
Лучший ответ

Прочитайте байт по байту за потоком, построив число 64Bit в порядке хоста-байта (так как это максимальная длина потока бит).
Затем извлеките, используя стандартную бит-скрипку.

Этот двухступенчатый рецепт имеет преимущество в отношении хозяина-эндианта-агностика.

Получение окна из n бит в индексе i:

uint64_t extract(uint64_t in, int n, int i) {
    return in<<(64-i-n)>>(64-n);
}
  • 0
    звучит как хорошая идея, но проблематично то, что компилятор WindRiver имеет длину всего 4 байта на 32-битной машине для PPC. Так что, если я имею дело со значением 48 бит, то это проблема. Хммм надо думать. Я подходил к нему побайтово: D. Кажется, лучше иметь дело с этим с точки зрения всего потока. Для значений больше 32 бит мне нужно хранить его в формате хоста, но с большим количеством байтов, чем примитивное длинное значение sizeof ().
  • 0
    длинный длинный -> там есть uint64_t. Теперь я должен прочитать весь поток и преобразовать его в формат хоста, а затем выполнить некоторые маскировки старших значащих битов, которые не являются частью данных, и сдвинуть вправо ненужные биты.
Показать ещё 5 комментариев
1

Мое предложенное решение:

pickbits.h

#ifndef PICKBITS_H_INCLUDED
#define PICKBITS_H_INCLUDED

#include <stddef.h>
#include <stdint.h>

extern uint64_t pick_bits(unsigned char *bytes, size_t nbytes, int lo, int hi);

#endif /* PICKBITS_H_INCLUDED */

Заголовки необходимы для size_t из <stddef.h> и uint64_t из <inttypes.h>. Важно, чтобы заголовки были самодостаточными и идемпотентными. Включение этих двух заголовков необходимо для того, чтобы сделать pickbits.h самодостаточным; защитники заголовков делают его идемпотентным, хотя они могут быть удалены, и все равно все будет в порядке, поскольку в коде нет определений типов (а стандартные заголовки уже ограничены идемпотентностью по стандарту C).

pickbits.c

#include "pickbits.h"
#include <assert.h>

uint64_t pick_bits(unsigned char *bytes, size_t nbytes, int lo, int hi)
{
  assert(bytes != 0 && nbytes > 0 && nbytes <= 8);
  assert(lo >= 0 && lo < 64);
  assert(hi >= 0 && hi < 64 && hi >= lo);
  uint64_t result = 0;
  for (int i = nbytes - 1; i >= 0; i--)
    result = (result << 8) | bytes[i];
  result >>= lo;
  result &= (UINT64_C(1) << (hi - lo + 1)) - 1;
  return result;
}

Обратите внимание, что в том числе "pickbits.h" сначала проверяет, что заголовок является самодостаточным. Макрос UINT64_C гарантирует, что константа 1 рассматривается как значение uint64_t.

picktest.c

#include "pickbits.h"
#include <inttypes.h>
#include <stdio.h>

int main(void)
{
  unsigned char d1[8] = "\xA5\xB4\xC3\xD2\xE1\xF0\x96\x87";
  /* Selecting nybbles */
  for (int u = 0; u < 64; u += 4)
  {
    uint64_t v = pick_bits(d1, sizeof(d1), u, u+3);
    printf("Picking bits %2d..%2d gives 0x%" PRIX64 "\n", u, u+3, v);
  }
  /* Select across nybble boundaries - T.B.D */
  return 0;
}

Тест должен быть расширен, чтобы пересечь границы низы, или остаться полностью в пределах шарлатанства.

Прогон образца

Picking bits  0.. 3 gives 0x5
Picking bits  4.. 7 gives 0xA
Picking bits  8..11 gives 0x4
Picking bits 12..15 gives 0xB
Picking bits 16..19 gives 0x3
Picking bits 20..23 gives 0xC
Picking bits 24..27 gives 0x2
Picking bits 28..31 gives 0xD
Picking bits 32..35 gives 0x1
Picking bits 36..39 gives 0xE
Picking bits 40..43 gives 0x0
Picking bits 44..47 gives 0xF
Picking bits 48..51 gives 0x6
Picking bits 52..55 gives 0x9
Picking bits 56..59 gives 0x7
Picking bits 60..63 gives 0x8

Почему не только один исходный файл?

Ответ: см. Почему GCC 4.8.2 жалуется на добавление при строгом переполнении?

В принципе, приведенный выше код компилируется строго под строгими предупреждениями:

$ gcc -g -O3 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Wold-style-declaration -Werror -c \
>     pickbits.c picktest.c
$

Если он интегрирован в один файл, "функция" GCC 4.8.2 запускается и генерирует предупреждение (которое -Werror преобразуется в ошибку), хотя ситуация, о которой она предупреждает, не может произойти (переполнение не может произойти если типы были int8_t, не говоря уже о int).

  • 0
    Я комбинирую этот pick_bits () с шагом, упомянутым дедупликатором выше.
  • 0
    Спасибо за усилия, которые вы вложили в это, у меня уже несколько месяцев стабильно работает код. Работает без проблем.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню