[英]Can I set a sequence of bits without unsetting the previous values?
我說了一些話
0110 [1011] 1111
假設我要將myddle nybble設置為0111
作為新值。
使用與AND
或OR
的位置屏蔽方法,我似乎別無選擇,只能先將原始值取消設置為0000
,因為如果我嘗試對原始值1011
AND
ing或OR
ing,則我不會預期結果為0111
。
我應該使用另一個邏輯運算符來獲得所需的效果嗎? 還是我每次都被鎖定兩次操作?
經過善意的協助,結果是:
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;
}
...我相信這會得到進一步的改進,但這是(半)可讀版本。
如果您碰巧已經知道這些位的當前值,則可以進行XOR:
0110 1011 1111
^ 0000 1100 0000
= 0110 0111 1111
(其中1100
需要計算為當前位與所需位之間的XOR)。
當然,這仍然是2個操作。 區別在於您可以在某些情況下預先計算第一個XOR。
除了這種特殊情況,沒有其他方法。 從根本上講,您需要表示3種狀態:設置為1,設置為0,不要更改。 您不能使用單個二進制操作數來執行此操作。
您可能需要使用位字段(如果希望能夠同時作為一組位字段和int來訪問結構,則可能要使用並集),類似於:
struct foo
{
unsigned int o1:4;
unsigned int o2:4;
unsigned int o3:4;
};
foo bar;
bar.o2 = 0b0111;
不知道它是否比您的清除/設置轉換成更有效的機器代碼...
嗯,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
但是在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
但是由於(S&~M)
〜M)的中間結果0110 0000 1111從未存儲在任何位置的變量中,所以我不會真正將其稱為“未設置”。 這只是一個按位的布爾表達式。 具有相同真值表的任何布爾表達式都可以使用。 這是另一個:
N = ((S^V) & M) ^ A; // corresponds to Oli Charlesworth's answer
相關的真值表:
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
^ ^
|____________________|
標有“ *”的行無所謂,因為它們不會發生(當未設置相應的掩碼位時,V中的位將永遠不會被設置)。 除了那些行外,表達式的真值表是相同的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.