2進数リテラルが欲しいときのまとめ
たとえば組み込みで,2進数っぽい文法で数値を扱いたいときがある.ドットマトリクスに顔文字アイコンを表示させるときに
set_icon_data( 0x0a, // 1 1 0x0a, // 1 1 0x00, // 0x11, // 1 1 0x0e // 111 );
みたいにベタ書きなのはあまりにも悲しい.顔文字をコードで直接記述したい!でもC/C++は2進表記を直接サポートしない.じゃあどうするか.
コンパイラの拡張構文を使う
コンパイラによっては"0b00100000"みたいなリテラルで2進数を扱える場合もある.4.3以降のgccでもそう.
set_icon_data( 0b01010, 0b01010, 0b00000, 0b10001, 0b01110 );
マクロでbinary literal風事前定義
2進数表記のようなマクロを事前に定義しておく.数が多いなら機械的に生成してあげればOK.
#define b00001 1 #define b00010 2 ... set_icon_data( b01010, b01010, b00000, b10001, b01110 );
1ビットシフトへの置換
次の手はプリプロセッサに頑張ってもらう方式.定数式なのでコンパイル時に全部計算され,機械語の時点では上と全く一緒になっている.
#define $ (((((0 #define X <<1|1) #define _ <<1) set_icon_data( $ _ _ _ _ _, $ _ X _ X _, $ _ X _ X _, $ _ _ _ _ _, $ X _ _ _ X, $ _ X X X _ );
アイコンっぽくて楽しい感じ.
8進数を介して2進リテラルもどきを生成
8進数で"1011"は2進数で"001 000 001 001"になる.文字列結合演算子##を使って8進数表現にしてから3nビット目をnビット目にマッピングすることで,"1011"から11を得ることができる.これも得られるバイナリは一緒.
#define PP_HEX2BIN(b) ( \ ((b & 1 << 0) >> 0) + ((b & 1 << 3) >> 2) + ((b & 1 << 6) >> 4) + \ ((b & 1 << 9) >> 6) + ((b & 1 << 12) >> 8) + ((b & 1 << 15) >> 10) + \ ((b & 1 << 18) >> 12) + ((b & 1 << 21) >> 14)) #define B(x) PP_HEX2BIN(0 ## x) set_icon_data( B(01010), B(01010), B(00000), B(10001), B(01110) );
(C++)boostを使う
上と似た機能はboostでも提供されているので,C++なら実装しなくてもよい.こっちは間にスペースが入っていてもOK.
#include <boost/utility/binary.hpp> #define B(x) BOOST_BINARY(x) set_icon_data( B(01010), B(01010), B(00000), B(10001), B(01110) ); // これでもOK #define _ 0 set_icon_data( B(_ 1 _ 1 _), B(_ 1 _ 1 _), B(_ _ _ _ _), B(1 _ _ _ 1), B(_ 1 1 1 _) );
(C++0x)constexpr
constexprを使ってコンパイル時に評価.演算子を使えると絵としての表現力が上がりますね!
参考:二進数リテラル(嘘) - とくにあぶなくないRiSKのブログ
set_icon_data( -+-+-b(), -+-+-b(), -----b(), +---+b(), -+++-b() );