简体   繁体   English

我可以设置一个位序列而不重置先前的值吗?

[英]Can I set a sequence of bits without unsetting the previous values?

I've got a sequence of bits, say 我说了一些话

0110 [1011] 1111

Let's say I want to set that myddle nybble to 0111 as the new value. 假设我要将myddle nybble设置为0111作为新值。

Using a positional masking approach with AND or OR , I seem to have no choice but to first unset the original value to 0000 , because if I trying AND ing or OR ing against that original value of 1011 , I'm not going to come out with the desired result of 0111 . 使用与ANDOR的位置屏蔽方法,我似乎别无选择,只能先将原始值取消设置为0000 ,因为如果我尝试对原始值1011 AND ing或OR ing,则我不会预期结果为0111

Is there another logical operator I should be using to get the desired effect? 我应该使用另一个逻辑运算符来获得所需的效果吗? Or am I locked into 2 operations every time? 还是我每次都被锁定两次操作?


The result after kindly assistance was: 经过善意的协助,结果是:

inline void foo(Clazz* parent, const Uint8& material, const bool& x, const bool& y, const bool& z)
{
    Uint8 offset = x | (y << 1) | (z << 2); //(0-7)
    Uint64 positionMask = 255 << offset * 8; //255 = length of each entry (8 bits), 8 = number of bits per material entry
    Uint64 value = material << offset * 8;
    parent->childType &= ~positionMask; //flip bits to clear given range.
    parent->childType |= value;
}

...I'm sure this will see further improvement, but this is the (semi-)readable version. ...我相信这会得到进一步的改进,但这是(半)可读版本。

If you happen to already know the current values of the bits, you can XOR: 如果您碰巧已经知道这些位的当前值,则可以进行XOR:

  0110 1011 1111
^ 0000 1100 0000

= 0110 0111 1111

(where the 1100 needs to be computed first as the XOR between the current bits and the desired bits). (其中1100需要计算为当前位与所需位之间的XOR)。

This is, of course, still 2 operations. 当然,这仍然是2个操作。 The difference is that you could precompute the first XOR in certain circumstances. 区别在于您可以在某些情况下预先计算第一个XOR。

Other than this special case, there is no other way. 除了这种特殊情况,没有其他方法。 You fundamentally need to represent 3 states: set to 1, set to 0, don't change. 从根本上讲,您需要表示3种状态:设置为1,设置为0,不要更改。 You can't do this with a single binary operand. 您不能使用单个二进制操作数来执行此操作。

You may want to use bit fields (and perhaps unions if you want to be able to access your structure as a set of bit fields and as an int at the same time) , something along the lines of: 您可能需要使用位字段(如果希望能够同时作为一组位字段和int来访问结构,则可能要使用并集),类似于:

struct foo
{  
unsigned int o1:4;  
unsigned int o2:4;  
unsigned int o3:4;   
};  

foo bar;  

bar.o2 = 0b0111; 

Not sure if it translates into more efficient machine code than your clear/set... 不知道它是否比您的清除/设置转换成更有效的机器代码...

Well, there's an assembly instruction in MMIX for this: 嗯,MMIX中有一个汇编指令:

SETL $1, 0x06BF ; 0110 1011 1111
SETL $2, 0x0070 ; 0000 0111 0000
SETL rM, 0x00F0 ; set mask register

MUX $1,$2,$1 ; result is 0110 0111 1111

But in C++ here's what you're probably thinking of as 'unsetting the previous value'. 但是在C ++中,您可能会想这就是“重置先前的值”。

int S = 0x6BF;      // starting value:   0110 1011 1111
int M = 0x0F0;      // value mask:       0000 1111 0000
int V = 0x070;      // value:            0000 0111 0000

int N = (S&~M) | V; // new value:        0110 0111 1111

But since the intermediate result 0110 0000 1111 from (S&~M) is never stored in a variable anywhere I wouldn't really call it 'unsetting' anything. 但是由于(S&~M) 〜M)的中间结果0110 0000 1111从未存储在任何位置的变量中,所以我不会真正将其称为“未设置”。 It's just a bitwise boolean expression. 这只是一个按位的布尔表达式。 Any boolean expression with the same truth table will work. 具有相同真值表的任何布尔表达式都可以使用。 Here's another one: 这是另一个:

N = ((S^V) & M) ^ A; // corresponds to Oli Charlesworth's answer

The related truth tables: 相关的真值表:

    S M V  (S& ~M) | V      ((S^V) & M) ^ S
    0 0 0    0 1   0           0   0    0
 *  0 0 1    0 1   1           1   0    0
    0 1 0    0 0   0           0   0    0
    0 1 1    0 0   1           1   1    1
    1 0 0    1 1   1           1   0    1
 *  1 0 1    1 1   1           0   0    1
    1 1 0    0 0   0           1   1    0
    1 1 1    0 0   1           0   0    1
                   ^                    ^
                   |____________________|

The rows marked with '*' don't matter because they won't occur (a bit in V will never be set when the corresponding mask bit is not set). 标有“ *”的行无所谓,因为它们不会发生(当未设置相应的掩码位时,V中的位将永远不会被设置)。 Except for those rows, the truth tables for the expressions are the same. 除了那些行外,表达式的真值表是相同的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM