Битовые операции в C++


Notice: Функция get_currentuserinfo с версии 4.5.0 считается устаревшей! Используйте wp_get_current_user(). in /hlds/web/u138079p19/code4life.ru/htdocs/wp-includes/functions.php on line 3840

Недавно понадобилось использовать упаковку двух int32_t в int64_t, понял что недостаточно знаний в области битовых операций, изучил, теперь сделаю заметку, все очень просто mail

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

Битовые операции могут создать значение отличное от 0 или 1, это следует учитывать при использовании таких операций в условиях.

Старший бит (high сокращенно hi)  находится слева, а младший (low сокращенно lo) — который справа.

Битовые операции:

& И
| ИЛИ
^ Исключающее ИЛИ
~ Инверсия
>> Сдвиг вправо
<< Сдвиг влево

Битовый оператор | ИЛИ (OR)

Работает также как и логический оператор ИЛИ, только над битами, выдает 1 в случае если один из операндов является 1 и 0 в противном случае:

  • 0 | 0 = 0
  • 0 | 1 = 1
  • 1 | 0 = 1
  • 1 | 1 = 1

Можно использовать для совмещения битовых масок:

  • 0x0000000F | 0xF0000000 = 0xF000000F

Битовый оператор & И (AND)

Работает также как и логический оператор И, только над битами, выдает 1 в случае оба операнда является 1 и 0 в противном случае:

  • 0 & 0 = 0
  • 0 & 1 = 0
  • 1 & 0 = 0
  • 1 & 1 = 1

Можно использовать для исключения битовых масок:

  • 0xF000000F & 0xF0000000 = 0xF0000000

То есть любой нулевой бит с правом или левом операнде установит в 0 аналогичный бит в итоговом значении.

Битовый оператор ^ исключающее ИЛИ (XOR)

Данный оператор устанавливает бит в 1 если биты в операндах отличаются, то есть:

  • 0x0111 ^ 0x0011 = 0x0100

Битовые операторы сдвигов >> <<

Синтаксис:

UINT uiNum;
...
//оператор сдвига влево на 8 бит
uiNum << 8;

//оператор сдвига право на 8 бит
uiNum >> 8;

Сдвинутые биты за пределы значения не вернуться с противоположной стороны, иными словами:

  • 01110000 << 2 = 11000000
  • 11000000 >> 2 = 00110000

Каждый сдвиг влево на 1 бит приводит к умножению значения на 2:

  • 00000001 << 1 = 00000010
  • 2 << 1 = 4

Каждый сдвиг вправо на 1 бит приводит к делению значения на 2:

  • 00000010 >> 1 = 00000001
  • 2 >> 1 = 1

Битовый оператор ~ НЕ (NOT)

Данный оператор инвертирует все биты в значении:

  • ~01010101 = 10101010
  • ~10101010 = 01010101

То есть операция полностью обратима повторным использованием.

Пример

Битовые операции могут использовать для упаковки нескольких значений меньшей разрядности в одно значение большей разрядности. К примеру упакуем 2 int32_t в int64_t и распакуем обратно:

uint64_t Encode(int32_t iNum1, int32_t iNum2)
{
	// записываем первое число
	uint64_t uiNum64 = (uint32_t)iNum1;
	// сдвигаем биты влево, подготавливая место для записи второго числа
	uiNum64 = uiNum64 << 32; 
	// записываем второе число
	uiNum64 = uiNum64 | ((uint32_t)iNum2); 
	return uiNum64; 
} 

void Decode(uint64_t uiNum64, int32_t &iNum1, int32_t &iNum2) 
{
	// сдвигаем биты вправо тем самым получаем записанное нами первое число
	iNum1 = (uint32_t)(uiNum64 >> 32);
	// исключаем старшие 32 бита
	iNum2 = (int32_t)(uint32_t)(uiNum64 & 0xFFFFFFFF);
}

Encode упаковывает 2 int32_t числа и возвращает uint64_t, а Decode распаковывает uint64_t.

Однако, все может быть еще проще:

/*! упаковка двух int32_t в uint64_t */ 
#define ENCODE2ID(id1, id2)( (((uint64_t)((uint32_t)id1))<<32) | (uint32_t)id2 ) 

/*! извлечение первого числа int32_t из упакованного uint32_t*/ 
#define DECODE2ID_HI(id)( (int32_t)(uint32_t)(((uint64_t)id) >> 32) )

/*! извлечение второго числа int32_t из упакованного uint32_t*/
#define DECODE2ID_LO(id)( (int32_t)(uint32_t)(((uint64_t)id) & 0xFFFFFFFF) )

Как видно, все чрезвычайно просто, надо было просто вникнуть в суть вопроса big_boss

Поделиться:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*