どのように少し設定、クリア、トグルしますか?
どのように少し設定、クリア、トグルしますか?
回答:
ビット単位のOR演算子(|
)を使用してビットを設定します。
number |= 1UL << n;
これにより、のn
thビットが設定されnumber
ます。stビットn
を設定する場合、1
stビットを設定する場合は0 までn-1
、n
thビットを設定する場合は0にする必要があります。
使用1ULL
場合は、number
より広いですunsigned long
。のプロモーションは、の幅を超えてシフトすることが未定義の動作である場所1UL << n
を評価するまで発生しません。残りのすべての例にも同じことが当てはまります。1UL << n
long
ビット単位のAND演算子(&
)を使用して、ビットをクリアします。
number &= ~(1UL << n);
これn
により、のthビットがクリアされnumber
ます。ビット文字列は、ビットごとのNOT演算子(~
)を使用して反転してから、ANDする必要があります。
XOR演算子(^
)を使用して、ビットを切り替えることができます。
number ^= 1UL << n;
これn
により、のth番目のビットが切り替わりますnumber
。
あなたはこれを要求しませんでしたが、私はそれを追加することもできます。
ビットを確認するには、数値nを右にシフトしてから、ビットごとのANDを実行します。
bit = (number >> n) & 1U;
これにより、のn
th番目のビットの値がnumber
変数に入れられますbit
。
設定n
のいずれかにビット目を1
または0
2の補数のC ++実装に次のように達成することができます:
number ^= (-x ^ number) & (1UL << n);
ビットがn
あれば設定されx
ている1
、とあればクリアx
です0
。場合はx
、いくつかの他の値を持っている、あなたはゴミを取得します。 x = !!x
0または1にブール値化します。
これを2の補数の否定動作(-1
1の補数や符号/大きさのC ++実装とは異なり、すべてのビットが設定されている場所)から独立させるには、符号なし否定を使用します。
number ^= (-(unsigned long)x ^ number) & (1UL << n);
または
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
一般に、移植可能なビット操作には符号なしの型を使用することをお勧めします。
または
number = (number & ~(1UL << n)) | (x << n);
(number & ~(1UL << n))
n
thビットをクリアし、thビットを(x << n)
に設定n
しx
ます。
また、一般的にコードをコピー/貼り付けしないことは一般的に良い考えであり、多くの人々はプリプロセッサマクロ(コミュニティのwikiの回答など)やある種のカプセル化を使用します。
bit = (number >> x) & 1
1
int
署名されたリテラルです。したがって、ここでのすべての操作は、標準では十分に定義されていない、署名された数値で動作します。標準は2の補数または算術シフトを保証しないため、を使用することをお勧めします1U
。
number = number & ~(1 << n) | (x << n);
はn番目のビットをxに変更することを好みます。
標準C ++ライブラリの使用:std::bitset<N>
。
またはBoostバージョン:boost::dynamic_bitset
。
自分でロールする必要はありません。
#include <bitset>
#include <iostream>
int main()
{
std::bitset<5> x;
x[1] = 1;
x[2] = 0;
// Note x[0-4] valid
std::cout << x << std::endl;
}
[Alpha:] > ./a.out
00010
Boostバージョンでは、標準ライブラリのコンパイル時サイズのビットセットと比較して、ランタイムサイズのビットセットを使用できます。
もう1つのオプションは、ビットフィールドを使用することです。
struct bits {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
};
struct bits mybits;
3ビットフィールドを定義します(実際には、3つの1ビットフィールドです)。ビット操作が少し簡単になりました(笑)。
ビットを設定またはクリアするには:
mybits.b = 1;
mybits.c = 0;
ビットを切り替えるには:
mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1; /* all work */
少しチェック:
if (mybits.c) //if mybits.c is non zero the next line below will execute
これは、固定サイズのビットフィールドでのみ機能します。それ以外の場合は、以前の投稿で説明されているビットトゥウィドルテクニックに頼る必要があります。
ヘッダーファイルで定義されたマクロを使用して、ビットセットとクリアを処理します。
/* a=target variable, b=bit number to act upon 0-n */
#define BIT_SET(a,b) ((a) |= (1ULL<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b)))
#define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b)))) // '!!' to make sure this returns 0 or 1
/* x=target variable, y=mask */
#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK_ALL(x,y) (((x) & (y)) == (y)) // warning: evaluates y twice
#define BITMASK_CHECK_ANY(x,y) ((x) & (y))
BITMASK_CHECK(x,y) ((x) & (y))
((x) & (y)) == (y)
それ以外の場合は、マルチビットマスクで不正な結果を返す必要があります(例:5
vs . 3
)/ *すべてのgravediggersに挨拶する:)* /
1
(uintmax_t)1
誰かがこれらのマクロを1 long
つ以上のタイプで使用しようとした場合、または類似している必要があります
BITMASK_CHECK_ALL(x,y)
として実装可能!~((~(y))|(x))
!(~(x) & (y))
ビットenum
に名前を付けるためにを使用する価値がある場合があります。
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
その後、名前を使用します。すなわち書く
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
設定、クリア、テスト。このようにして、残りのコードからマジックナンバーを隠します。
それ以外はジェレミーの解決策を支持します。
clearbits()
代わりに関数を作成することもできます&= ~
。なぜこれに列挙型を使用しているのですか?それらは任意の値が隠された一連の一意の変数を作成するためのものだと思いましたが、それぞれに明確な値を割り当てています。では、変数として定義するだけの利点は何でしょうか?
enum
関連する定数のセットにsを使用することは、cプログラミングではかなり前に遡ります。最近のコンパイラーでは、const short
明示的にグループ化されていることの唯一の利点、またはそれ以上の利点があると思います。そして、ビットマスク以外のもののためにそれらを必要とするとき、あなたは自動ナンバリングを得ます。もちろん、C ++では、それらは別個の型も形成し、静的なエラーチェックを少し追加します。
enum ThingFlags
値は何ThingError|ThingFlag1
ですか?
int
。これは、暗黙の整数の昇格または符号付きの型に対するビットごとの演算のため、あらゆる種類の微妙なバグを引き起こす可能性があります。thingstate = ThingFlag1 >> 1
たとえば、実装定義の動作を呼び出します。thingstate = (ThingFlag1 >> x) << y
未定義の動作を呼び出すことができます。等々。安全のため、常に符号なしの型にキャストしてください。
enum My16Bits: unsigned short { ... };
/*
** Bit set, clear, and test operations
**
** public domain snippet by Bob Stout
*/
typedef enum {ERROR = -1, FALSE, TRUE} LOGICAL;
#define BOOL(x) (!(!(x)))
#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))
では、分析してみましょう...
これらすべてに問題があると思われる一般的な表現は「(1L <<(posn))」です。これが行うことは、シングルビットがオンのマスクを作成することだけであり、これは任意の整数型で機能します。「posn」引数は、ビットが必要な位置を指定します。posn == 0の場合、この式は次のように評価されます。
0000 0000 0000 0000 0000 0000 0000 0001 binary.
posn == 8の場合、次のように評価されます。
0000 0000 0000 0000 0000 0001 0000 0000 binary.
つまり、指定された位置に1の0のフィールドを作成するだけです。唯一のトリッキーな部分はBitClr()マクロで、1のフィールドに単一の0ビットを設定する必要があります。これは、チルダ(〜)演算子で示されるのと同じ式の1の補数を使用することで実現されます。
マスクが作成されると、ビットごとの(&)、または(|)、およびxor(^)演算子を使用して、提案したとおりに引数に適用されます。マスクはlong型なので、マクロはchar、short、int、longでも同様に機能します。
要するに、これは問題のクラス全体に対する一般的な解決策であるということです。もちろん、これらのマクロと同等のものを必要なときに毎回明示的なマスク値で書き換えることは可能であり、適切でさえありますが、なぜそれを行うのですか?マクロの置換はプリプロセッサで行われるため、生成されたコードは値がコンパイラによって一定であると見なされるという事実を反映します。つまり、一般化されたマクロを使用するのは、必要になるたびに「ホイールを再発明」するのと同じくらい効率的です。ビット操作を行います。
納得できない?ここにいくつかのテストコードがあります-私は完全な最適化でWatcom Cを使用し、_cdeclを使用しなかったので、結果の逆アセンブリは可能な限りクリーンになります:
---- [TEST.C] ----------------------------------------- -----------------------
#define BOOL(x) (!(!(x)))
#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))
int bitmanip(int word)
{
word = BitSet(word, 2);
word = BitSet(word, 7);
word = BitClr(word, 3);
word = BitFlp(word, 9);
return word;
}
---- [TEST.OUT(逆アセンブル)] -------------------------------------- ---------
Module: C:\BINK\tst.c
Group: 'DGROUP' CONST,CONST2,_DATA,_BSS
Segment: _TEXT BYTE 00000008 bytes
0000 0c 84 bitmanip_ or al,84H ; set bits 2 and 7
0002 80 f4 02 xor ah,02H ; flip bit 9 of EAX (bit 1 of AH)
0005 24 f7 and al,0f7H
0007 c3 ret
No disassembly errors
---- [finis] ------------------------------------------- ----------------------
arg
ですlong long
。 1L
そう、可能な限り広いタイプである必要があります(uintmax_t)1
。(あなたはで逃げるかもしれません1ull
)
ビット演算子を使用します。 &
|
最後のビットを設定するには000b
:
foo = foo | 001b
最後のビットをチェックするにはfoo
:
if ( foo & 001b ) ....
の最後のビットをクリアするにはfoo
:
foo = foo & 110b
XXXb
わかりやすくするために使用しました。ビットをパックするデータ構造に応じて、おそらくHEX表現で作業します。
foo = foo ^ MY_MASK
foo = foo & ~MY_MASK
初心者のために、例を使ってもう少し説明したいと思います。
例:
value is 0x55;
bitnum : 3rd.
&
オペレータは、ビットをチェックに使用されます。
0101 0101
&
0000 1000
___________
0000 0000 (mean 0: False). It will work fine if the third bit is 1 (then the answer will be True)
トグルまたはフリップ:
0101 0101
^
0000 1000
___________
0101 1101 (Flip the third bit without affecting other bits)
|
演算子:ビットを設定する
0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)
ここから符号なし整数配列のいずれかのタイプのために働く私のお気に入りのビット算術演算マクロ、ですunsigned char
までsize_t
(と仕事への効率的であるべき最大のタイプであるが):
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof *(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof *(a)))))
ビットを設定するには:
BITOP(array, bit, |=);
少しクリアするには:
BITOP(array, bit, &=~);
ビットを切り替えるには:
BITOP(array, bit, ^=);
少しテストするには:
if (BITOP(array, bit, &)) ...
等
BITOP(array, bit++, |=);
ループで使用すると、呼び出し元が望んでいることはほとんど行われません。
BITCELL(a,b) |= BITMASK(a,b);
(両方のテイクa
引数としては、サイズを決定するために、後者は評価することはないa
ので、にのみ表示されますsizeof
)。
(size_t)
のキャストは一部だけを確実にするために存在しているようだ符号なしの数学をして%
。(unsigned)
そこにできた。
(size_t)(b)/(8*sizeof *(a))
不必要に狭めることができb
、分割前。非常に大きなビット配列に関する問題のみ。まだ面白いマクロです。
これには「組み込み」というタグが付いているので、マイクロコントローラーを使用していると想定します。上記の提案はすべて有効であり、機能します(読み取り、変更、書き込み、共用体、構造体など)。
しかし、オシロスコープベースのデバッグの最中に、これらの方法は、値がマイクロのPORTnSET / PORTnCLEARレジスターに直接書き込むのと比べて、CPUサイクルでかなりのオーバーヘッドがあり、タイトなループがある場所/高い場所で実際の違いがあることに驚いていました周波数ISRのトグルピン。
これらの不慣れな方のために:私の例では、マイクロに出力ピンを反映する一般的なピン状態レジスタPORTnがあるため、PORTn | = BIT_TO_SETを実行すると、そのレジスタへの読み取り-変更-書き込みが行われます。ただし、PORTnSET / PORTnCLEARレジスタは、「このビットを1にしてください」(SET)または「このビットをゼロにしてください」(CLEAR)を意味する「1」と「ピンをそのままにする」ことを意味する「0」を取ります。したがって、ビットを設定またはクリアするかどうかに応じて(常に便利ではない)2つのポートアドレスが返されますが、反応ははるかに速く、アセンブルされたコードは小さくなります。
volatile
ため、コンパイラはそのようなレジスタを含むコードに対して最適化を実行できないことに注意してください。したがって、そのようなコードを逆アセンブルし、アセンブラレベルでどのように機能するかを確認することをお勧めします。
ビットフィールドアプローチには、組み込み分野で他の利点があります。特定のハードウェアレジスタのビットに直接マップする構造体を定義できます。
struct HwRegister {
unsigned int errorFlag:1; // one-bit flag field
unsigned int Mode:3; // three-bit mode field
unsigned int StatusCode:4; // four-bit status code
};
struct HwRegister CR3342_AReg;
ビットパッキング順序に注意する必要があります。これはMSBが最初だと思いますが、これは実装に依存する場合があります。また、コンパイラーがバイト境界を越えるフィールドをどのように処理するかを確認します。
その後、以前と同様に、個々の値の読み取り、書き込み、テストを行うことができます。
#define bit_test(x, y) ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )
使用例:
int main(void)
{
unsigned char arr[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
for (int ix = 0; ix < 64; ++ix)
printf("bit %d is %d\n", ix, bit_test(arr, ix));
return 0;
}
注: これは、高速で(柔軟性を考慮して)分岐しないように設計されています。Sun Studio 8をコンパイルすると、効率的なSPARCマシンコードが生成されます。また、amd64でMSVC ++ 2008を使用してテストしました。ビットを設定およびクリアするための同様のマクロを作成することが可能です。このソリューションと他の多くのソリューションとの主な違いは、ほとんどすべてのタイプの変数の任意の場所で機能することです。
より一般的には、任意のサイズのビットマップの場合:
#define BITS 8
#define BIT_SET( p, n) (p[(n)/BITS] |= (0x80>>((n)%BITS)))
#define BIT_CLEAR(p, n) (p[(n)/BITS] &= ~(0x80>>((n)%BITS)))
#define BIT_ISSET(p, n) (p[(n)/BITS] & (0x80>>((n)%BITS)))
CHAR_BIT
は既にで定義されているためlimits.h
、独自に組み込む必要はありませんBITS
(実際にそうすることでコードが悪化します)
このプログラムは、データビットを0から1または1から0に変更します。
{
unsigned int data = 0x000000F0;
int bitpos = 4;
int bitvalue = 1;
unsigned int bit = data;
bit = (bit>>bitpos)&0x00000001;
int invbitvalue = 0x00000001&(~bitvalue);
printf("%x\n",bit);
if (bitvalue == 0)
{
if (bit == 0)
printf("%x\n", data);
else
{
data = (data^(invbitvalue<<bitpos));
printf("%x\n", data);
}
}
else
{
if (bit == 1)
printf("elseif %x\n", data);
else
{
data = (data|(bitvalue<<bitpos));
printf("else %x\n", data);
}
}
}
少しいじくり回している場合は、全体をより速くするマスクを使用することをお勧めします。次の関数は非常に高速で、柔軟性があります(任意のサイズのビットマップでビットをいじることができます)。
const unsigned char TQuickByteMask[8] =
{
0x01, 0x02, 0x04, 0x08,
0x10, 0x20, 0x40, 0x80,
};
/** Set bit in any sized bit mask.
*
* @return none
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
void TSetBit( short bit, unsigned char *bitmap)
{
short n, x;
x = bit / 8; // Index to byte.
n = bit % 8; // Specific bit in byte.
bitmap[x] |= TQuickByteMask[n]; // Set bit.
}
/** Reset bit in any sized mask.
*
* @return None
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
void TResetBit( short bit, unsigned char *bitmap)
{
short n, x;
x = bit / 8; // Index to byte.
n = bit % 8; // Specific bit in byte.
bitmap[x] &= (~TQuickByteMask[n]); // Reset bit.
}
/** Toggle bit in any sized bit mask.
*
* @return none
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
void TToggleBit( short bit, unsigned char *bitmap)
{
short n, x;
x = bit / 8; // Index to byte.
n = bit % 8; // Specific bit in byte.
bitmap[x] ^= TQuickByteMask[n]; // Toggle bit.
}
/** Checks specified bit.
*
* @return 1 if bit set else 0.
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
short TIsBitSet( short bit, const unsigned char *bitmap)
{
short n, x;
x = bit / 8; // Index to byte.
n = bit % 8; // Specific bit in byte.
// Test bit (logigal AND).
if (bitmap[x] & TQuickByteMask[n])
return 1;
return 0;
}
/** Checks specified bit.
*
* @return 1 if bit reset else 0.
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
short TIsBitReset( short bit, const unsigned char *bitmap)
{
return TIsBitSet(bit, bitmap) ^ 1;
}
/** Count number of bits set in a bitmap.
*
* @return Number of bits set.
*
* @param bitmap - Pointer to bitmap.
* @param size - Bitmap size (in bits).
*
* @note Not very efficient in terms of execution speed. If you are doing
* some computationally intense stuff you may need a more complex
* implementation which would be faster (especially for big bitmaps).
* See (http://graphics.stanford.edu/~seander/bithacks.html).
*/
int TCountBits( const unsigned char *bitmap, int size)
{
int i, count = 0;
for (i=0; i<size; i++)
if (TIsBitSet(i, bitmap))
count++;
return count;
}
16ビット整数のビット 'n'を設定するには、次のようにします。
TSetBit( n, &my_int);
ビット番号が渡したビットマップの範囲内にあることを確認するのはあなた次第です。バイト、ワード、dword、qwordなどがリトルエンディアンプロセッサの場合、メモリ内で相互に正しくマッピングされることに注意してください(リトルエンディアンプロセッサがビッグエンディアンプロセッサよりも「優れている」主な理由は、ああ、私は炎の戦争がやって来るのを感じますオン...)。
これを使って:
int ToggleNthBit ( unsigned char n, int num )
{
if(num & (1 << n))
num &= ~(1 << n);
else
num |= (1 << n);
return num;
}
bitset
答えを拡張する:
#include <iostream>
#include <bitset>
#include <string>
using namespace std;
int main() {
bitset<8> byte(std::string("10010011");
// Set Bit
byte.set(3); // 10010111
// Clear Bit
byte.reset(2); // 10010101
// Toggle Bit
byte.flip(7); // 00010101
cout << byte << endl;
return 0;
}
LinuxカーネルでCプログラミングを使用してこのすべての操作を実行する場合は、Linuxカーネルの標準APIを使用することをお勧めします。
https://www.kernel.org/doc/htmldocs/kernel-api/ch02s03.htmlを参照してください
set_bit Atomically set a bit in memory
clear_bit Clears a bit in memory
change_bit Toggle a bit in memory
test_and_set_bit Set a bit and return its old value
test_and_clear_bit Clear a bit and return its old value
test_and_change_bit Change a bit and return its old value
test_bit Determine whether a bit is set
注:ここでは、操作全体が1つのステップで行われます。したがって、これらはすべてSMPコンピューターでもアトミックであることが保証されており、プロセッサー間で一貫性を保つのに役立ちます。
Visual C 2010、およびおそらく他の多くのコンパイラーは、組み込みのブール演算を直接サポートしています。ビットにはブール値と同じように2つの値があり、ブール値を使用できます。この表現のメモリ。これは機能しsizeof()
ますが、オペレーターでも正しく機能します。
bool IsGph[256], IsNotGph[256];
// Initialize boolean array to detect printable characters
for(i=0; i<sizeof(IsGph); i++) {
IsGph[i] = isgraph((unsigned char)i);
}
だから、あなたの質問にIsGph[i] =1
、またはIsGph[i] =0
、ブールの設定とクリアを簡単にしてください。
印刷できない文字を見つけるには:
// Initialize boolean array to detect UN-printable characters,
// then call function to toggle required bits true, while initializing a 2nd
// boolean array as the complement of the 1st.
for(i=0; i<sizeof(IsGph); i++) {
if(IsGph[i]) {
IsNotGph[i] = 0;
} else {
IsNotGph[i] = 1;
}
}
このコードには「特別な」ものは何もないことに注意してください。それは少し整数のように扱います-技術的にはそうです。2つの値と2つの値のみを保持できる1ビット整数。
私はかつてこのアプローチを使用して、6桁のローン番号をビット配列へのインデックスとして使用し、loan_numberがISAMキーである重複したローンレコードを見つけました。非常に速く、8か月後、データの取得元であるメインフレームシステムが実際に誤動作していることが証明されました。ビット配列の単純さにより、たとえば検索アプローチと比較して、ビット配列の正確さが非常に高くなります。
bool
。int
実装に使用するC89セットアップでは、たぶん4バイトbool
ここに私が使用するいくつかのマクロがあります:
SET_FLAG(Status, Flag) ((Status) |= (Flag))
CLEAR_FLAG(Status, Flag) ((Status) &= ~(Flag))
INVALID_FLAGS(ulFlags, ulAllowed) ((ulFlags) & ~(ulAllowed))
TEST_FLAGS(t,ulMask, ulBit) (((t)&(ulMask)) == (ulBit))
IS_FLAG_SET(t,ulMask) TEST_FLAGS(t,ulMask,ulMask)
IS_FLAG_CLEAR(t,ulMask) TEST_FLAGS(t,ulMask,0)
int set_nth_bit(int num, int n){
return (num | 1 << n);
}
int clear_nth_bit(int num, int n){
return (num & ~( 1 << n));
}
int toggle_nth_bit(int num, int n){
return num ^ (1 << n);
}
int check_nth_bit(int num, int n){
return num & (1 << n);
}
check_nth_bit
もできますbool
。
最初に
num = 55
整数でビット単位の操作(設定、取得、クリア、トグル)を実行するとします。
n = 4
ビット単位の演算を実行する0ベースのビット位置。
nth
numビットの右シフトを取得するにはnum
、n
時間。次に&
、1とビットごとのAND を実行します。bit = (num >> n) & 1;
使い方?
0011 0111 (55 in decimal)
>> 4 (right shift 4 times)
-----------------
0000 0011
& 0000 0001 (1 in decimal)
-----------------
=> 0000 0001 (final result)
n
回。次に、ビットごとのOR |
演算をで実行しnum
ます。num |= (1 << n); // Equivalent to; num = (1 << n) | num;
使い方?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
0001 0000
| 0011 0111 (55 in decimal)
-----------------
=> 0001 0000 (final result)
n
つまり1 << n
。~ (1 << n)
ます。&
上記の結果とビット単位のAND 演算を実行しnum
ます。上記の3つのステップをまとめると、次のようになりnum & (~ (1 << n))
ます。num &= (~(1 << n)); // Equivalent to; num = num & (~(1 << n));
使い方?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
~ 0001 0000
-----------------
1110 1111
& 0011 0111 (55 in decimal)
-----------------
=> 0010 0111 (final result)
ビットを切り替えるには、ビットごとのXOR ^
演算子を使用します。ビットごとのXOR演算子は、両方のオペランドの対応するビットが異なる場合は1と評価され、それ以外の場合は0と評価されます。
つまり、ビットをトグルするということです。トグルするビットと1でXOR演算を実行する必要があります。
num ^= (1 << n); // Equivalent to; num = num ^ (1 << n);
使い方?
0 ^ 1 => 1
。 1 ^ 1 => 0
。 0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
0001 0000
^ 0011 0111 (55 in decimal)
-----------------
=> 0010 0111 (final result)
推奨読書- ビットごとのオペレーター演習
シングルビットをどのように設定、クリア、トグルしますか?
マスクを作成しようとするときに一般的なコーディングの落とし穴に対処するに
1
は、必ずしも十分な幅があるとは限りません
number
より広いタイプの場合、どのような問題が発生し1
ますか?未定義の動作(UB)につながる
x
シフトには大きすぎるかもしれません。それほど大きくなくても、最上位ビットが十分にフリップされない場合があります。1 << x
x
~
// assume 32 bit int/unsigned
unsigned long long number = foo();
unsigned x = 40;
number |= (1 << x); // UB
number ^= (1 << x); // UB
number &= ~(1 << x); // UB
x = 10;
number &= ~(1 << x); // Wrong mask, not wide enough
1の幅が十分であることを保証するには:
コードを使用し1ull
たり、コードを変更したり(uintmax_t)1
して、コンパイラーを最適化できます。
number |= (1ull << x);
number |= ((uintmax_t)1 << x);
またはキャスト-キャストを正しく最新に保つためにコーディング/レビュー/メンテナンスの問題を引き起こします。
number |= (type_of_number)1 << x;
または優しく促進1
の種類として少なくとも同じ幅である数学の操作を強制的にnumber
。
number |= (number*0 + 1) << x;
仕事に最善の最もビット操作と同様に、符号なしのタイプではなく、署名したもの
number |= (type_of_number)1 << x;
こともnumber |= (number*0 + 1) << x;
適切ではありません...実際、どちらもそうではありませんnumber |= (1ull << x);
。位置によってそれを行うポータブルな方法はありますか?
C ++ 11テンプレートバージョン(ヘッダーに配置):
namespace bit {
template <typename T1, typename T2> inline void set (T1 &variable, T2 bit) {variable |= ((T1)1 << bit);}
template <typename T1, typename T2> inline void clear(T1 &variable, T2 bit) {variable &= ~((T1)1 << bit);}
template <typename T1, typename T2> inline void flip (T1 &variable, T2 bit) {variable ^= ((T1)1 << bit);}
template <typename T1, typename T2> inline bool test (T1 &variable, T2 bit) {return variable & ((T1)1 << bit);}
}
namespace bitmask {
template <typename T1, typename T2> inline void set (T1 &variable, T2 bits) {variable |= bits;}
template <typename T1, typename T2> inline void clear(T1 &variable, T2 bits) {variable &= ~bits;}
template <typename T1, typename T2> inline void flip (T1 &variable, T2 bits) {variable ^= bits;}
template <typename T1, typename T2> inline bool test_all(T1 &variable, T2 bits) {return ((variable & bits) == bits);}
template <typename T1, typename T2> inline bool test_any(T1 &variable, T2 bits) {return variable & bits;}
}
;
関数定義の後にあるのですか?)
(variable & bits == bits)
?
((variable & bits) == bits)
std::bitset
c ++ 11での使用
このプログラムは、@ Jeremyの上記のソリューションに基づいています。誰かがすぐに遊びたいなら。
public class BitwiseOperations {
public static void main(String args[]) {
setABit(0, 4); // set the 4th bit, 0000 -> 1000 [8]
clearABit(16, 5); // clear the 5th bit, 10000 -> 00000 [0]
toggleABit(8, 4); // toggle the 4th bit, 1000 -> 0000 [0]
checkABit(8,4); // check the 4th bit 1000 -> true
}
public static void setABit(int input, int n) {
input = input | ( 1 << n-1);
System.out.println(input);
}
public static void clearABit(int input, int n) {
input = input & ~(1 << n-1);
System.out.println(input);
}
public static void toggleABit(int input, int n) {
input = input ^ (1 << n-1);
System.out.println(input);
}
public static void checkABit(int input, int n) {
boolean isSet = ((input >> n-1) & 1) == 1;
System.out.println(isSet);
}
}
Output :
8
0
0
true
C言語で次の関数のいずれかを試して、nビットを変更します。
char bitfield;
// Start at 0th position
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) ));
}
または
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n)));
}
または
void chang_n_bit(int n, int value)
{
if(value)
bitfield |= 1 << n;
else
bitfield &= ~0 ^ (1 << n);
}
char get_n_bit(int n)
{
return (bitfield & (1 << n)) ? 1 : 0;
}
value << n
未定義の動作を引き起こす可能性があります