サーチ…
備考
ビットシフト動作は、すべてのプロセッサアーキテクチャにわたって移植可能ではなく、異なるプロセッサは異なるビット幅を有することができる。言い換えれば、あなたが書いた
int a = ~0;
int b = a << 1;
この値は、64ビットマシンと32ビットマシン、またはx86ベースプロセッサからPICベースプロセッサにかけて異なります。
エンディアンは、ビット単位の操作自体で考慮する必要はありません。つまり、右シフト( >>
)はビットを最下位ビットにシフトし、XORは排他的またはビットを実行します。エンディアンはデータそのものを考慮する必要があります。つまり、エンディアンがアプリケーションにとって懸念される場合、ビット単位の操作に関係なく問題になります。
& - ビットAND
int a = 6; // 0110b (0x06)
int b = 10; // 1010b (0x0A)
int c = a & b; // 0010b (0x02)
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
出力
a = 6, b = 10, c = 2
なぜ
ビット単位でAND
演算がビットレベルで動作し、次のブール真理値表を使用します。
TRUE AND TRUE = TRUE
TRUE AND FALSE = FALSE
FALSE AND FALSE = FALSE
a
( 0110
)のバイナリ値とb
( 1010
)のバイナリ値がAND
結ばれると、 0010
バイナリ値が得られます。
int a = 0 1 1 0
int b = 1 0 1 0 &
---------
int c = 0 0 1 0
ビット単位のANDは、ビット単位の代入演算子&=
を使用することに特に割り当てられていない限り、元の値の値を変更しません。
int a = 5; // 0101b (0x05)
a &= 10; // a = 0101b & 1010b
| - ビットOR
int a = 5; // 0101b (0x05)
int b = 12; // 1100b (0x0C)
int c = a | b; // 1101b (0x0D)
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
出力
a = 5, b = 12, c = 13
なぜ
ビット単位のOR
は、ビットレベルで動作し、次のブール真理値表を使用します。
true OR true = true
true OR false = true
false OR false = false
a
( 0101
)のバイナリ値とb
( 1100
)のバイナリ値がOR
れると、バイナリ値1101
得られます。
int a = 0 1 0 1
int b = 1 1 0 0 |
---------
int c = 1 1 0 1
ビット単位の論理和演算子|=
を使用することに特に割り当てられていない限り、ビット単位のORは元の値の値を変更しません。
int a = 5; // 0101b (0x05)
a |= 12; // a = 0101b | 1101b
^ - ビットごとのXOR(排他的論理和)
int a = 5; // 0101b (0x05)
int b = 9; // 1001b (0x09)
int c = a ^ b; // 1100b (0x0C)
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
出力
a = 5, b = 9, c = 12
なぜ
ビット単位でXOR
(排他的OR)はビットレベルで動作し、次のブール真理値表を使用します。
true OR true = false
true OR false = true
false OR false = false
XOR演算のtrue OR true = false
、演算のtrue AND/OR true = true
、したがってXOR演算の排他的性質に注意してください。
これを使用して、 a
( 0101
)のバイナリ値とb
( 1001
)のバイナリ値がXOR
れると、 1100
バイナリ値が得られます。
int a = 0 1 0 1
int b = 1 0 0 1 ^
---------
int c = 1 1 0 0
ビット単位のXORは、ビット単位の代入演算子^=
を使用することに特に割り当てられていない限り、元の値の値を変更しません。
int a = 5; // 0101b (0x05)
a ^= 9; // a = 0101b ^ 1001b
ビット単位のXORは、多くの点で利用でき、暗号化と圧縮のためのビットマスク操作でよく使用されます。
注:以下の例は、しばしば素晴らしいトリックの例として示されています。しかし、本番用のコードでは使用しないでくださいstd::swap()
同じ結果を得るためのstd::swap()
方が良い方法があります)。
また、XOR演算を利用して、2つの変数を一時的に交換することもできます。
int a = 42;
int b = 64;
// XOR swap
a ^= b;
b ^= a;
a ^= b;
std::cout << "a = " << a << ", b = " << b << "\n";
これを生産するには、それを使用できることを確認するために小切手を追加する必要があります。
void doXORSwap(int& a, int& b)
{
// Need to add a check to make sure you are not swapping the same
// variable with itself. Otherwise it will zero the value.
if (&a != &b)
{
// XOR swap
a ^= b;
b ^= a;
a ^= b;
}
}
だから、それは単なる素晴らしいテクニックのように見えますが、実際のコードでは役に立ちません。 xorは基本論理演算ではなく、他の組み合わせである:a ^ c =〜(a&c)&(a | c)
2015+のコンパイラ変数でも、バイナリとして割り当てることができます:
int cn=0b0111;
〜〜ビット単位のNOT(単項補数)
unsigned char a = 234; // 1110 1010b (0xEA)
unsigned char b = ~a; // 0001 0101b (0x15)
std::cout << "a = " << static_cast<int>(a) <<
", b = " << static_cast<int>(b) << std::endl;
出力
a = 234, b = 21
なぜ
ビットワイズNOT
(単項補数)はビットレベルで動作し、単純に各ビットを反転します。それはだ場合は1
、に変わったの0
それはだ場合は、 0
、それが変わったの1
。ビットワイズNOTは、特定のタイプの最大値に対して値をXORするのと同じ効果を持ちます。
unsigned char a = 234; // 1110 1010b (0xEA)
unsigned char b = ~a; // 0001 0101b (0x15)
unsigned char c = a ^ ~0;
ビットワイズNOTは、特定の整数型の最大値をチェックする便利な方法です。
unsigned int i = ~0;
unsigned char c = ~0;
std::cout << "max uint = " << i << std::endl <<
"max uchar = " << static_cast<short>(c) << std::endl;
ビットワイズNOTは、元の値の値を変更せず、複合代入演算子を持たないため、例えばa ~= 10
を実行a ~= 10
ことはできません。
ビットワイズ NOT( ~
)は論理 NOT( !
)と混同しないでください。論理的NOTはその値を使って操作を行います(!1) != (~1)
つまり、 (!1) != (~1)
<< - 左シフト
int a = 1; // 0001b
int b = a << 1; // 0010b
std::cout << "a = " << a << ", b = " << b << std::endl;
出力
a = 1, b = 2
なぜ
左のビットのワイズシフトは、左の値( a
)のビットを右( 1
)に指定された数だけシフトし、基本的に最下位ビットを0で埋め込み、 5
(2進0000 0101
) 4回(例えば、 5 << 4
)は80
(2進数0101 0000
)の値をもたらす。値を左に1回シフトすることも、値に2を掛けることと同じです(例:
int a = 7;
while (a < 200) {
std::cout << "a = " << a << std::endl;
a <<= 1;
}
a = 7;
while (a < 200) {
std::cout << "a = " << a << std::endl;
a *= 2;
}
しかし、左シフト操作では、符号ビットを含むすべてのビットが左にシフトされます(例:
int a = 2147483647; // 0111 1111 1111 1111 1111 1111 1111 1111
int b = a << 1; // 1111 1111 1111 1111 1111 1111 1111 1110
std::cout << "a = " << a << ", b = " << b << std::endl;
可能な出力: a = 2147483647, b = -2
コンパイラによっては期待される結果が得られるものもありますが、符号ビットが影響を受けるように符号付き数値をシフトしたままにした場合、結果は不定になります。シフトするビットの数が負の数であるか、または左の型が保持できるビットの数よりも大きい場合は、 未定義です(例:
int a = 1;
int b = a << -1; // undefined behavior
char c = a << 20; // undefined behavior
ビット単位の左シフトは、ビット単位の割り当て複合演算子<<=
を使用することに特に割り当てられていない限り、元の値の値を変更しません。
int a = 5; // 0101b
a <<= 1; // a = a << 1;
>> - 右シフト
int a = 2; // 0010b
int b = a >> 1; // 0001b
std::cout << "a = " << a << ", b = " << b << std::endl;
出力
a = 2, b = 1
なぜ
右ビットワイズシフトは、左の値( a
)のビットを右( 1
)に指定された数にシフトします。右シフトの動作は標準であるが、 符号付き負の数の右シフトのビットには何が起こるのかは実装定義であるため、移植性が保証されないことに注意するべきである。
int a = -2;
int b = a >> 1; // the value of b will be depend on the compiler
シフトするビット数が負の数である場合は、これも不定です(例:
int a = 1;
int b = a >> -1; // undefined behavior
ビット単位の右シフトは、ビット単位の割り当て複合演算子>>=
を使用することに特に割り当てられていない限り、元の値の値を変更しません。
int a = 2; // 0010b
a >>= 1; // a = a >> 1;