ビット毎の設定
プログラム上で、ビット毎にフラグの意味を持たせてOn/Offを切り替えることって、ありますよね?
複数のフラグを同時に設定できるので、便利な考え方です。
※ハードウエアの制御やAPIで使われていたり、自作する場合などがあると思います。
フラグの設定
フラグ用の定数が用意されている場合は、値を意識することはあまりないですが
自分で記述しなければならないことがあります。
その場合、例えばフラグ0と6と7をOnにしたいとなれば、まず2進数で考えます。
フラグ0と6と7をOnにする2進数
1100 0001
2進数リテラルを使わない(なかったころの)場合は、ビット毎の設定に適した16進数に変換します。
いきなりは難しいので、4ビット毎に10進数に変換して、そこから16進数に変換です。
先程のフラグ0と6と7をOnにする2進数を表に従って置き換えてみます。
10進数に変換(4ビット毎)
12 1
16進数に変換
C 1
ここまで来てやっとプログラムに記述が可能です。
フラグ0と6と7をOnにする(C++)
uint8_t flag = 0xC1; // 0xは16進数リテラルであることを示す宣言
フラグ0と6と7をOnにする(C#)
byte flag = 0xC1; // 0xは16進数リテラルであることを示す宣言
ダメじゃないけど、16進数に興味ないし、回りくどいし直感的じゃないですよね…
そこで、2進数リテラルの登場です!!!
フラグ0と6と7をOnにする(2進数リテラル利用)
// C++での記述 (C++14から可能)
uint8_t flag = 0b11000001; // 0bは2進数リテラルであることを示す宣言
フラグ0と6と7をOnにする(2進数リテラル利用)
// C#での記述 (C# 7.0から可能)
byte flag = 0b11000001; // 0bは2進数リテラルであることを示す宣言
どうでしょう。直感的ではないでしょうか?
えっ、見にくい? …ですよね。そこで区切り文字が使えます。
フラグ0と6と7をOnにする(2進数リテラル利用)
// C++での記述 (C++14から可能)
uint8_t flag = 0b1100'0001; // 0bは2進数リテラルであることを示す宣言
フラグ0と6と7をOnにする(2進数リテラル利用)
// C#での記述 (C# 7.0から可能)
byte flag = 0b1100_0001; // 0bは2進数リテラルであることを示す宣言
※C++は「'」シングルクォーテーションでC#は「_」アンダースコアが区切り文字です。
区切り文字とは、プログラム上の意味は存在しないが可読性のために記述できる文字の事です。
これで4桁ずつ区切れば、可読性も問題ないのではないでしょうか。
定数を作る場合もこんな感じになって見やすいです。
フラグ0と6と7をOnにする(2進数リテラル利用)
// C++での記述 (C++14から可能)
static const uint8_t FLAG0 = 0b0000'0001;
static const uint8_t FLAG1 = 0b0000'0010;
static const uint8_t FLAG2 = 0b0000'0100;
static const uint8_t FLAG3 = 0b0000'1000;
static const uint8_t FLAG4 = 0b0001'0000;
static const uint8_t FLAG5 = 0b0010'0000;
static const uint8_t FLAG6 = 0b0100'0000;
static const uint8_t FLAG7 = 0b1000'0000;
// 定数を使ってフラグ0と6と7をOnにする(C++)
uint8_t flag = FLAG0 | FLAG6 | FLAG7;
フラグ0と6と7をOnにする(2進数リテラル利用)
// C#での記述 (C# 7.0から可能)
const byte FLAG0 = 0b0000_0001;
const byte FLAG1 = 0b0000_0010;
const byte FLAG2 = 0b0000_0100;
const byte FLAG3 = 0b0000_1000;
const byte FLAG4 = 0b0001_0000;
const byte FLAG5 = 0b0010_0000;
const byte FLAG6 = 0b0100_0000;
const byte FLAG7 = 0b1000_0000;
// 定数を使ってフラグ0と6と7をOnにする(C#)
byte flag = FLAG0 | FLAG6 | FLAG7;