ビット演算子
C言語のビット演算子について解説します。ビット演算とは、1ビット単位で行われる演算のことをいいます。
ビットAND演算子 | & |
---|---|
ビットOR演算子 | | |
ビットXOR演算子 | ^ |
ビットNOT演算子 | ~ |
ビットAND演算子
ビットAND演算子「&」は、二つのオペランドに含まれるあるビットが両方とも1の場合に、返却する値の対応する位置に1に設定し、あるビットのどちらかが0の場合は0を設定します。
# ビットAND x & y
xとyが両方とも8bit符号なし整数型であるとしましょう。zがビットAND演算子の結果の値です。xとyのある位置の両方のビットが1の場合に、対応するzのビットも1になり、それ以外の場合は0になります。
x 01001100 y 01000101 z 01000100
ビットAND演算子のサンプルです。
#include <stdio.h> #include <stdint.h> int main(void) { // 01001100 uint8_t x = 0x4C; // 01000101 uint8_t y = 0x45; // 01000100 uint8_t z = x & y; printf("%X\n", z); }
出力結果です。16進数での出力ですが、2進数であれば「01000100」です。
44
ビットOR演算子
ビットOR演算子「|」は、二つのオペランドに含まれるあるビットのどちらかが1(どちらも1でもよい)の場合に、返却する値の対応する位置に1に設定し、あるビットの両方が0の場合は0を設定します。
# ビットOR x | y
xとyが両方とも8bit符号なし整数型であるとしましょう。zがビットOR演算子の結果の値です。xとyのある位置のどちらかのビットが1の場合に、対応するzのビットも1になり、両方とも0の場合は0になります。
x 01001100 y 01000101 z 01001101
ビットOR演算子のサンプルです。
#include <stdio.h> #include <stdint.h> int main(void) { // 01001100 uint8_t x = 0x4C; // 01000101 uint8_t y = 0x45; // 01001101 uint8_t z = x | y; printf("%X\n", z); }
出力結果です。16進数での出力ですが、2進数であれば「01001101」です。
4D
ビットXOR演算子
ビットXOR演算子「^」は、二つのオペランドに含まれるあるビットがのどちらかだけが1の場合に、返却する値の対応する位置に1に設定し、あるビットの両方が0あるいは1の場合は0を設定します。
# ビットXOR x ^ y
xとyが両方とも8bit符号なし整数型であるとしましょう。zがビットXOR演算子の結果の値です。xとyのある位置のどちらかだけのビットが1の場合に、対応するzのビットも1になり、両方とも0または1の場合は0になります。
x 01001100 y 01000101 z 00001001
ビットXOR演算子のサンプルです。
#include <stdio.h> #include <stdint.h> int main(void) { // 01001100 uint8_t x = 0x4C; // 01000101 uint8_t y = 0x45; // 0001001 uint8_t z = x ^ y; printf("%X\n", z); }
出力結果です。16進数での出力ですが、2進数であれば「0001001」です。
9
ビットNOT演算子
ビットNOT演算子「~」は、オペランドに含まれるあるビットを反転させます。
# ビットNOT ~x
xとyが両方とも8bit符号なし整数型であるとしましょう。zがビットNOT演算子の結果の値です。xのビットが反転しています。
x 01001100 z 10110011
ビットNOT演算子のサンプルです。出力結果は、整数型拡張の影響をなくすために「0xFF」とのビットANDをとっています。
#include <stdio.h> #include <stdint.h> int main(void) { // 01001100 uint8_t x = 0x4C; // 01000101 uint8_t y = 0x45; // 10110011 uint8_t z = ~x; printf("%X\n", z); }
出力結果です。16進数での出力で、すが、2進数であれば「01000100」です。
B3
ビット演算子と「=」を組み合わせた特殊演算子
ビット演算子と「=」を組み合わせた特殊演算子があります。
# 「x = x & y」 と同じ意味 x &= y # 「x = x | y」 と同じ意味 x |= y # 「x = x ^ y」 と同じ意味 x ^= y
ビット演算子は実務ではどのような場合に使用しますか?
ビット演算子を一番使う場面は、フラグを関数の引数に渡す場合です。C言語では、フラグを、整数で渡すことが多いのですが、その場合に、ビットの位置で意味を定めます。列挙型enumを使って、各ビットのフラグを定義します。1(二進で1), 2(二進で10), 4(二進で100), 8(二進で1000)。
各ビットを立てるときはビットOR「|=」、落とすときはビットXOR「^=」です。
ビットが立っているかをチェックするときは「&」を使います。
関数の引数に渡すフラグを作成するサンプルコードです。
#include <stdio.h> #include <stdint.h> enum { MYAPP_FLAG1 = 1, MYAPP_FLAG2 = 2, MYAPP_FLAG3 = 4, MYAPP_FLAG4 = 8, MYAPP_FLAG5 = 16, MYAPP_FLAG6 = 32, MYAPP_FLAG7 = 64, MYAPP_FLAG8 = 128, MYAPP_FLAG9 = 256, MYAPP_FLAG10 = 512, }; int main(void) { uint32_t flag = 0; // MYAPP_FLAG4をたてる flag |= MYAPP_FLAG4; // 00000000 00000000 00000000 00001000 printf("%X\n", flag); // MYAPP_FLAG10をたてる flag |= MYAPP_FLAG10; // 00000000 00000000 00000010 00001000 printf("%X\n", flag); // MyAPP_FLAG4を落とす flag ^= MYAPP_FLAG4; // 00000000 00000000 00000010 00000000 printf("%X\n", flag); // ビットが立っているかチェック if (flag & MYAPP_FLAG10) { printf("MYAPP_FLAG10 ok\n"); } }