Побитовое индексирование в C?

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

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

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

Спасибо -

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
0
7 607
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

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

Чтобы установить 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 и AND:

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

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

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

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

Это поможет?

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

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

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

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

varabile |= 1 << bit_index;

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

variable &= ~( 1 << bit_index );

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

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

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

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

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

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

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

Mark Ingram 15.09.2008 17:55

Нет, дело в vector <bool> и boost :: dynamic_bitset в том, что они используют один бит на bool. Для хранения 1024 bool они будут использовать 128 байтов плюс служебные данные класса. Как вы рассчитали в 32 раза больше места для хранения, чем необходимо?

janm 30.09.2008 18:57

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

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

Теория

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

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

1101
0100
---- AND
0100

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

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

1101
0010
---- OR
1111

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

Пример

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

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

Ответ принят как подходящий

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

It is possible.

To set the nth bit, use OR:

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

To clear a bit, use AND:

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

To flip a bit, use XOR:

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

Или же...

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

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

Определите такую ​​структуру:

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;

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

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