побитовая индексация в C? - PullRequest
7 голосов
/ 15 сентября 2008

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

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

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

Спасибо -

Ответы [ 9 ]

10 голосов
/ 15 сентября 2008

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

Это возможно.

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

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

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

x & = ~ (1 << 5); // очищает Шестые-с-справа </p>

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

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

Или ...

#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
}
7 голосов
/ 15 сентября 2008

Возможно.

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

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

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

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

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

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

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

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

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

3 голосов
/ 15 сентября 2008

Посмотрите ответы на этот вопрос .

2 голосов
/ 15 сентября 2008

Theory

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

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

1101
0100
---- AND
0100

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

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

1101
0010
---- OR
1111

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

Пример

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

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

1 голос
/ 15 сентября 2008

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

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

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;

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

1 голос
/ 15 сентября 2008

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

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

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

varabile |= 1 << bit_index;

Чтобы перезапустить бит:

variable &= ~( 1 << bit_index );
0 голосов
/ 15 сентября 2008

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

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

0 голосов
/ 15 сентября 2008

Существует стандартный контейнер библиотеки для битов: std :: vector. Он специализируется на библиотеке для экономии места. Также имеется класс boost_bitset.

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

Увеличение документации динамического набора битов

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

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

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

0 голосов
/ 15 сентября 2008

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

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

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

bit = char & 0xF0;

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

очевидно, вам нужно изменить маску, чтобы получить разные биты (примечание: 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

Это поможет?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...