Как заменить биты в битовом поле, не влияя на другие биты, используя c
Я хотел заменить бит/биты (более 1) в 32/64 бит данных, не затрагивая другие биты. Например, например:
У меня есть 64-битный регистр, где биты 5 и 6 могут принимать значения 0,1,2,3.
5:6
0 0
0 1
1 0
1 1
Теперь, когда я читаю регистр, я получаю значение слова 0x146 (0001 0 10 0 0110). Теперь я хочу изменить значение в позиции бит 5 и 6 на 01. (сейчас это 10, которое равно 2 в десятичной и я хочу заменить его на 1 e 01), если другие биты не будут затронуты, и запишите регистр только с измененными битами 5 и 6 (поэтому после изменения становится 126)
Я пробовал делать это
reg_data=0x146
reg_data |= 1 << shift (shift in this case is 5)
Если я делаю это значение в позициях бит 5 & 6 станет 11 (0x3), а не 01 (0x1), который я хотел.
- Как мне делать чтение/изменение/запись?
- Как заменить только определенные бит/биты в 32-битных полях, не затрагивая все данные поля, используя C?
Настройка бит в порядке, но более одного бита, мне сложно это сделать.
Любые предложения приветствуются.
Ответы
Ответ 1
Почему бы вам не использовать битовую маску? Пример:
new_value = 0, 1, 2 or 3 // (this is the value you will set in)
bit_mask = (3<<5) // (mask of the bits you want to set)
reg_data = (reg_data & (~bit_mask)) | (new_value<<5)
Это сохраняет старые биты и OR в новых.
Ответ 2
reg_data &= ~( (1 << shift1) | (1 << shift2) );
reg_data |= ( (1 << shift1) | (1 << shift2) );
Первая строка очищает два бита в (shift1, shift2), а вторая строка устанавливает их.
Ответ 3
Вот общий процесс, который действует на длинный массив, считая его длинным битовым полем и каждый отдельный адрес бит
#define set_bit(arr,x) ((arr[(x)>>3]) |= (0x01 << ((x) & 0x07)))
#define clear_bit(arr,x) (arr[(x)>>3] &= ~(0x01 << ((x) & 0x07)))
#define get_bit(arr,x) (((arr[(x)>>3]) & (0x01 << ((x) & 0x07))) != 0)
Просто использует индекс, который использует нижние 3 бита индекса, чтобы идентифицировать 8 разных позиций битов внутри каждого местоположения массива char, а верхние биты остатка - адреса, в которых расположено расположение бит, обозначенное символом x
, Надеюсь, это поможет.
Edit1:
Чтобы установить бит, вам нужно ИЛИ или целевое слово с другим словом с 1 в этой конкретной позиции бита и 0 во всех остальных с целью. Все 0 в других положениях гарантируют, что существующий 1 в цели будет таким же, как и во время OR, а 1 в определенных положениях гарантирует, что цель получит 1 в этой позиции. если у нас есть mask = 0x02 = 00000010 (1 байт), тогда мы можем ИЛИ это любому слову, чтобы установить бит pos
target = 1 0 1 1 0 1 0 0
OR + + + + + + + +
mask 0 0 0 0 0 0 1 0
---------------
answer 1 0 1 1 0 1 1 0
Чтобы очистить бит, вам нужно И целевое слово с другим словом с 0 в этой конкретной позиции бит и всего 1. Все 1 во всех других положениях бит обеспечивают, чтобы во время И цель сохраняла свои 0 и 1 так, как они были в этих местах, а 0 в разрядной позиции, подлежащей очистке, также устанавливало бы эту позицию бит 0 в целевом слове. если у нас есть одна и та же маска = 0x02, тогда мы можем подготовить эту маску для очистки с помощью ~ mask
mask = 0 0 0 0 0 0 1 0
~mask = 1 1 1 1 1 1 0 1
AND . . . . . . . .
target 1 0 1 1 0 1 1 0
---------------
answer 1 0 1 1 0 1 0 0
Ответ 4
Вопрос был о том, как реализовать в C, но так как все поиски "заменить биты" приводят сюда, я приведу свою реализацию в VB.Net. Это был unit тест. Для тех, кому интересно, как ToBinaryString
расширение ToBinaryString
: Convert.ToString(value,2)
''' <summary>
''' Replace the bits in the enumValue with the bits in the bits parameter, starting from the position that corresponds to 2 to the power of the position parameter.
''' </summary>
''' <param name="enumValue">The integer value to place the bits in.</param>
''' <param name="bits">The bits to place. It must be smaller or equal to 2 to the power of the position parameter.</param>
'''<param name="length">The number of bits that the bits should replace.</param>
''' <param name="position">The exponent of 2 where the bits must be placed.</param>
''' <returns></returns>
''' <remarks></remarks>'
<Extension>
Public Function PlaceBits(enumValue As Integer, bits As Integer, length As Integer, position As Integer) As Integer
If position > 31 Then
Throw New ArgumentOutOfRangeException(String.Format("The position {0} is out of range for a 32 bit integer.",
position))
End If
Dim positionToPlace = 2 << position
If bits > positionToPlace Then
Throw New ArgumentOutOfRangeException(String.Format("The bits {0} must be smaler than or equal to {1}.",
bits, positionToPlace))
End If
'Create a bitmask (a series of ones for the bits to retain and a series of zeroes for bits to discard).'
Dim mask As Integer = (1 << length) - 1
'Use for debugging.'
'Dim maskAsBinaryString = mask.ToBinaryString'
'Shift the mask to left to the desired position'
Dim leftShift = position - length + 1
mask <<= leftShift
'Use for debugging.'
'Dim shiftedMaskAsBinaryString = mask.ToBinaryString'
'Shift the bits to left to the desired position.'
Dim shiftedBits = bits << leftShift
'Use for debugging.'
'Dim shiftedBitsAsBinaryString = shiftedBits.ToBinaryString'
'First clear (And Not) the bits to replace, then set (Or) them.'
Dim result = (enumValue And Not mask) Or shiftedBits
'Use for debugging.'
'Dim resultAsBinaryString = result.ToBinaryString'
Return result
End Function
Ответ 5
-
Примените маску против битового поля, чтобы сохранить биты, которые вы не хотите изменять. Это также очистит биты, которые вы будете менять.
-
Убедитесь, что у вас есть битовое поле, содержащее только те биты, которые вы хотите установить/очистить.
-
Либо используйте оператор "или" для двух битовых полей, либо просто добавьте их.
Например, если вы хотите изменить только биты с 2 по 5 на основе ввода от 0 до 15.
byte newVal = (byte)value & 0x0F;
newVal = (byte)value << 2;
oldVal = oldVal & 0xC3;
oldVal = oldval + newVal;
Ответ 6
Вам нужно будет делать это по одному бит за раз. Используйте то, что вы сейчас делаете, чтобы установить бит в один, и используйте следующее, чтобы установить что-то в 0:
reg_data &= ~ (1 << shift)
Ответ 7
Вы можете использовать эту динамическую логику для любого количества бит и в любом битовом поле. В основном, у вас есть 3 части в битовой последовательности чисел -
MSB_SIDE | CHANGED_PART | LSB_SIDE
CHANGED_PART может быть перемещен в крайнюю сторону MSB или LSB.
Шаги по замене количества битов следующие: 1. Возьмите только часть MSB_SIDE и замените все оставшиеся биты на 0. 2. Обновите новую битовую последовательность, добавив желаемую битовую последовательность в определенной позиции. 3. Обновите всю битовую последовательность с помощью LSB_SIDE исходной битовой последовательности.
org_no = 0x53513C;
upd_no = 0x333;
start_pos = 0x6, bit_len = 0xA;
temp_no = 0x0;
temp_no = org_no & (0xffffffff << (bit_len+start_pos)); //this is step 1
temp_no |= upd_no << start_pos; //this is step 2
org_no = temp_no | (org_no & ~(0xffffffff << start_pos)); //this is step 3'
Примечание. Маскирование с 0xffffffff считается 32-битным. Вы можете изменить соответственно вашему требованию.