C语言 如何使用c替换位域中的位而不影响其他位
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5925755/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to replace bits in a bitfield without affecting other bits using c
提问by Unicorn
I wanted to replace bit/bits(more than 1) in a 32/64 bit data field without affecting other bits.Say for example:
我想在不影响其他位的情况下替换 32/64 位数据字段中的位/位(大于 1)。例如:
I have a 64 bit register where bits 5&6 can take values 0,1,2,3.
我有一个 64 位寄存器,其中第 5 位和第 6 位可以取值 0、1、2、3。
5:6
0 0
0 1
1 0
1 1
Now when i read the register i get say value 0x146(0001 0 10 0 0110).Now i want to change the value at bit position 5 and 6 to 01.(right now it is 10 which is 2 in decimal and i want to replace it to 1 e 01) without other bits getting affected and write back the register with only bits 5&6 modified.(so it become 126 after changing)
现在,当我读取寄存器时,我得到值 0x146(0001 0 10 0 0110)。现在我想将第 5 位和第 6 位的值更改为 01。(现在是 10,这是十进制的 2,我想将其替换为 1 e 01) 而不会影响其他位并仅修改位 5&6 写回寄存器。(因此更改后变为 126)
I tried doing this
我试过这样做
reg_data=0x146
reg_data |= 1 << shift (shift in this case is 5)
If i do this value at bit positions 5& 6 will become 11(0x3) not 01(0x1) which i wanted.
如果我在位位置 5 和 6 处执行此值将变为 11(0x3) 而不是我想要的 01(0x1)。
- How do i go about doing read/modify/write?
- How do i replace only certain bit/bits in a 32/64 bit fields without affecting the whole data of the field using C?
- 我如何进行读/修改/写?
- 如何使用 C 仅替换 32/64 位字段中的某些位/位而不影响该字段的整个数据?
Setting a bit is okay but more than one bit, i am finding it little difficult.
设置一点是可以的,但不止一点,我发现这有点困难。
Any suggestions are highly appreciated.
任何建议都非常感谢。
回答by vy32
Why don't you use a bitmask? Sort of like:
为什么不使用位掩码?有点像:
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)
This preserves the old bits and OR's in the new ones.
这将保留旧位和新位中的 OR。
回答by Amardeep AC9MF
reg_data &= ~( (1 << shift1) | (1 << shift2) );
reg_data |= ( (1 << shift1) | (1 << shift2) );
The first line clears the two bits at (shift1, shift2) and the second line sets them.
第一行清除 (shift1, shift2) 处的两位,第二行设置它们。
回答by phoxis
Here is a generic process which acts on a long array considering it a long bitfield and addresses each bit position individually
这是一个通用过程,它作用于一个长数组,将它视为一个长位域,并单独寻址每个位位置
#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)
Simply takes the index uses the lower 3 btis of the index to identify 8 different bit positions inside each location of the char array, and the upper remainder bits addresses in which array location does the bit denoted by xoccur. Hope this helps.
简单地获取索引使用索引的低3位来标识char数组的每个位置内的8个不同位位置,并且高余位地址在数组位置中x出现表示的位。希望这可以帮助。
Edit1:To set a bit you need to OR the target word with another word with 1 in that specific bit position and 0 in all other with the the target. All 0's in the other positions ensure that the existing 1's in the target are as it is during OR, and the 1 in the specific positions ensures that the target gets the 1 in that position. if we have mask = 0x02 = 00000010 (1 byte) then we can OR this to any word to set that bit pos
Edit1:要设置一个位,您需要将目标字与另一个字进行或,该特定位位置为 1,所有其他字为 0 与目标。其他位置的所有 0 确保目标中现有的 1 在 OR 期间保持原样,特定位置的 1 确保目标在该位置获得 1。如果我们有掩码 = 0x02 = 00000010(1 个字节),那么我们可以将其与任何字进行 OR 运算以设置该位 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
To clear a bit you need to AND the target word with another word with 0 in that specific bit position and 1 in all. All 1 in all other bit positions ensure that during AND the target preserves its 0's and 1's as they were in those locations, and a 0 in the bit position to be cleared would also set that bit position 0 in the target word. if we have the same mask = 0x02, then we can prepare this mask for clearing by ~mask
要清除一个位,您需要将目标字与另一个在该特定位位置为 0 且总共为 1 的字进行 AND 运算。所有其他位位置中的全 1 确保在 AND 期间目标保留其在这些位置中的 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
回答by Dabblernl
The question was about how to implement in C, but as al searches for "replace bits" lead to here I will supply my implementation in VB.Net. It has been unit test tested. For those who are wondering what the ToBinaryStringextension looks like: Convert.ToString(value,2)
问题是关于如何在 C 中实现,但由于搜索“替换位”导致这里我将在 VB.Net 中提供我的实现。它已经过单元测试测试。对于那些想知道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
回答by dave
Apply a mask against the bitfield to maintain the bits that you do not want to change. This will also clear out the bits that you will be changing.
Ensure that you have a bitfield that contains only the bits that you want to set/clear.
Either use the or operator to "or" the two bitfields, or just simply add them.
对位域应用掩码以维护您不想更改的位。这也将清除您将要更改的位。
确保您有一个只包含您要设置/清除的位的位域。
要么使用 or 运算符“或”两个位域,要么只是简单地添加它们。
For instance, if you wanted to only change bits 2 thru 5 based on input of 0 thru 15.
例如,如果您只想根据 0 到 15 的输入更改位 2 到 5。
byte newVal = (byte)value & 0x0F;
newVal = (byte)value << 2;
oldVal = oldVal & 0xC3;
oldVal = oldval + newVal;
回答by Chris Eberle
You'll need to do that one bit at a time. Use the or like you're currently doing to set a bit to one, and use the following to set something to 0:
你需要一次做一点。使用您当前正在执行的或类似的操作将某个位设置为 1,然后使用以下命令将某项设置为 0:
reg_data &= ~ (1 << shift)
回答by Avik
You can use this dynamic logic for any number of bit and in any bit field. Basically, you have 3 parts in a bit sequence of number -
您可以将此动态逻辑用于任意数量的位和任意位字段。基本上,您在数字的位序列中有 3 个部分 -
MSB_SIDE | CHANGED_PART | LSB_SIDE
MSB_SIDE | CHANGED_PART | LSB_SIDE
The CHANGED_PART can be moved up to extreme MSB or LSB side.
CHANGED_PART 可以向上移动到极端 MSB 或 LSB 侧。
The steps to replace a number of bit(s) are as follows - 1. Take only MSB_SIDE part and replace all the remaining bits with 0. 2. Update the new bit sequence by adding your desired bit sequence in particular position. 3. Update the entire bit sequence with LSB_SIDE of the original bit sequence.
替换多个位的步骤如下 - 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`
Note: The masking with 0xffffffff is considered as 32bit. You can change accordingly with your requirement.
注意:0xffffffff 的掩码被认为是 32 位。您可以根据您的要求进行相应更改。

