Вопрос

Я пытаюсь реализовать идею сжатия данных, которая у меня была, и поскольку я представляю себе ее выполнение с большим объемом тестовых данных, я подумал закодировать ее на C (в основном у меня есть опыт работы со скриптовыми языками, такими как Ruby и Tcl.)

Просматривая книги О'Рейли "корова" по C, я понимаю, что не могу просто проиндексировать биты простой переменной типа 'char' или 'int', как мне хотелось бы, для выполнения побитовых сравнений и операторов.

Прав ли я в своем восприятии?Разумно ли для меня использовать перечислимый тип для представления бита (и создать массив из них, а также написать функции для преобразования в символ и из него)?Если да, то определен ли такой тип и функции уже где-нибудь в стандартной библиотеке?Существуют ли другие (лучшие?) подходы?Есть ли где-нибудь какой-нибудь пример кода, на который кто-нибудь мог бы мне указать?

Спасибо -

Это было полезно?

Решение

Исходя из того, что сказал Кайл, вы можете использовать макрос, который выполнит всю тяжелую работу за вас.

Это вполне возможно.

Чтобы установить n-й бит, используйте ИЛИ:

x |= (1 << 5);// устанавливает 6-й-от справа

Чтобы немного очистить, используйте И:

x &= ~(1 << 5);// очищается 6-й справа

Чтобы немного перевернуть, используйте XOR:

x ^= (1 << 5);// переворачивает 6-й справа

Или...

#define GetBit(var, bit) ((var & (1 << bit)) != 0) // Returns true / false if bit is set
#define SetBit(var, bit) (var |= (1 << bit))
#define FlipBit(var, bit) (var ^= (1 << bit))

Затем вы можете использовать это в коде типа:

int myVar = 0;
SetBit(myVar, 5);
if (GetBit(myVar, 5))
{
  // Do something
}

Другие советы

Это вполне возможно.

Чтобы установить n-й бит, используйте ИЛИ:

x |= (1 << 5); // sets the 5th-from right

Чтобы немного очистить, используйте И:

x &= ~(1 << 5); // clears 5th-from-right

Чтобы немного перевернуть, используйте XOR:

x ^= (1 << 5); // flips 5th-from-right

Чтобы получить значение бита, используйте shift и И:

(x & (1 << 5)) >> 5 // gets the value (0 or 1) of the 5th-from-right

примечание:сдвиг вправо на 5 предназначен для того, чтобы убедиться, что значение равно либо 0, либо 1.Если вас просто интересует 0 / не 0, вы можете обойтись без сдвига.

Взгляните на ответы на этот вопрос.

Теория

Не существует синтаксиса C для доступа или установки n-го бита встроенного типа данных (напримерa "символ").Однако вы можете получить доступ к битам с помощью логической операции "И" и установить биты с помощью логической операции "ИЛИ".

В качестве примера предположим, что у вас есть переменная, которая содержит 1101, и вы хотите проверить 2-й бит слева.Просто выполните логическое И с 0100:

1101
0100
---- AND
0100

Если результат отличен от нуля, то, должно быть, был установлен 2-й бит;в противном случае это не было задано.

Если вы хотите установить 3-й бит слева, то выполните логическое ИЛИ с 0010:

1101
0010
---- OR
1111

Вы можете использовать операторы C && (для AND) и || (для OR) для выполнения этих задач.Вам нужно будет самостоятельно создать шаблоны доступа к битам (0100 и 0010 в приведенных выше примерах).Хитрость заключается в том, чтобы помнить, что младший значащий бит (LSB) отсчитывает 1 секунду, следующий LSB отсчитывает 2 секунды, затем 4 секунды и т.д.Итак, шаблон доступа к битам для n-го LSB (начинающийся с 0) - это просто значение 2 ^ n.Самый простой способ вычислить это на C - сдвинуть двоичное значение 0001 (в этом четырехразрядном примере) влево на требуемое количество мест.Поскольку это значение всегда равно 1 в целочисленных величинах без знака, это просто '1 << н'

Пример

unsigned char myVal = 0x65; /* in hex; this is 01100101 in binary. */

/* Q: is the 3-rd least significant bit set (again, the LSB is the 0th bit)? */
unsigned char pattern = 1;
pattern <<= 3; /* Shift pattern left by three places.*/

if(myVal && (char)(1<<3)) {printf("Yes!\n");} /* Perform the test. */

/* Set the most significant bit. */
myVal |= (char)(1<<7);

Этот пример не был протестирован, но должен послужить иллюстрацией общей идеи.

Для запроса состояния бита с определенным индексом:

int index_state = variable & ( 1 << bit_index );

Для установки бита:

varabile |= 1 << bit_index;

Для перезапуска бита:

variable &= ~( 1 << bit_index );

Отдельные биты могут быть проиндексированы следующим образом.

Определите структуру, подобную этой:

struct
{
  unsigned bit0     : 1;
  unsigned bit1     : 1;
  unsigned bit2     : 1;
  unsigned bit3     : 1;
  unsigned reserved : 28;
} bitPattern;   

Теперь, если я хочу узнать отдельные битовые значения переменной с именем "value", выполните следующие действия:

CopyMemory( &input, &value, sizeof(value) );

Чтобы узнать, является ли бит 2 высоким или низким:

int state = bitPattern.bit2;

Надеюсь, это поможет.

Попробуйте использовать битовые поля.Будьте осторожны, реализация может варьироваться в зависимости от компилятора.

http://publications.gbdirect.co.uk/c_book/chapter6/bitfields.html

ЕСЛИ вы хотите немного проиндексировать, вы могли бы:

bit = (char & 0xF0) >> 7;

возвращает msb символа.Вы могли бы даже опустить правую смену и выполнить тест на 0.

bit = char & 0xF0;

если бит установлен, то результат будет > 0;

очевидно, вам нужно изменить маску, чтобы получить другие биты (NB:0xF - это битовая маска, если она неясна).Можно определить множество масок, например

#define BIT_0 0x1 // or 1 << 0
#define BIT_1 0x2 // or 1 << 1
#define BIT_2 0x4 // or 1 << 2
#define BIT_3 0x8 // or 1 << 3

и т.д...

Это дает вам:

bit = char & BIT_1;

Вы можете использовать эти определения в приведенном выше коде для успешной индексации бита либо в макросе, либо в функции.

Чтобы установить бит:

char |= BIT_2;

Чтобы немного очистить:

char &= ~BIT_3

Чтобы немного переключиться

char ^= BIT_4

Эта помощь?

Существует стандартный библиотечный контейнер для битов:std:: вектор.Он специализируется на том, чтобы библиотека была компактной.Существует также класс boost dynamic_bitset.

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

Документация по динамическому набору битов Boost

Документацию по STL смотрите в документации вашего компилятора.

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

Комментатору, который утверждал, что это занимает в 32 раза больше места, чем необходимо:boost::dynamic_bitset и vector специализированы на использовании одного бита для каждой записи, и поэтому нет штрафа за пробел, предполагая, что вы на самом деле хотите больше, чем количество битов в примитивном типе.Эти классы позволяют вам адресовать отдельные биты в большом контейнере с эффективным базовым хранилищем.Если вам просто нужны (скажем) 32 бита, во что бы то ни стало используйте int .Если вам нужно какое-то большое количество битов, вы можете использовать библиотечный контейнер.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top