C言語でソースコードに直接2進数を書きたい場合がある(ような種類の業務がある)。
で。
C言語なのでマクロで実現する。
関数で実現すると enum に入れられないとか、いろいろ困るので。
軽く検索するとすぐに実装例が見つかり、例えば
http://www.kmc.gr.jp/~tak/memo/c-binary.html
に正解があるんだけど、せっかくなのでちょっと改変したバージョンを。
binary_macro.c
// compiled with clang -std=c99 -Wall
#include <stdint.h> // to use UINT64_C
#include <stdio.h>
#include <assert.h>
#define B(b) (\
((UINT64_C(0##b)>> 0) & 7 ? (1U<< 0) : 0U) | \
((UINT64_C(0##b)>> 3) & 7 ? (1U<< 1) : 0U) | \
((UINT64_C(0##b)>> 6) & 7 ? (1U<< 2) : 0U) | \
((UINT64_C(0##b)>> 9) & 7 ? (1U<< 3) : 0U) | \
((UINT64_C(0##b)>>12) & 7 ? (1U<< 4) : 0U) | \
((UINT64_C(0##b)>>15) & 7 ? (1U<< 5) : 0U) | \
((UINT64_C(0##b)>>18) & 7 ? (1U<< 6) : 0U) | \
((UINT64_C(0##b)>>21) & 7 ? (1U<< 7) : 0U) | \
((UINT64_C(0##b)>>24) & 7 ? (1U<< 8) : 0U) | \
((UINT64_C(0##b)>>27) & 7 ? (1U<< 9) : 0U) | \
((UINT64_C(0##b)>>30) & 7 ? (1U<<10) : 0U) | \
((UINT64_C(0##b)>>33) & 7 ? (1U<<11) : 0U) | \
((UINT64_C(0##b)>>36) & 7 ? (1U<<12) : 0U) | \
((UINT64_C(0##b)>>39) & 7 ? (1U<<13) : 0U) | \
((UINT64_C(0##b)>>42) & 7 ? (1U<<14) : 0U) | \
((UINT64_C(0##b)>>45) & 7 ? (1U<<15) : 0U) | \
((UINT64_C(0##b)>>48) & 7 ? (1U<<16) : 0U) | \
((UINT64_C(0##b)>>51) & 7 ? (1U<<17) : 0U) | \
((UINT64_C(0##b)>>54) & 7 ? (1U<<18) : 0U) | \
((UINT64_C(0##b)>>57) & 7 ? (1U<<19) : 0U) | \
((UINT64_C(0##b)>>60) & 7 ? (1U<<20) : 0U) | \
((UINT64_C(0##b)>>63) & 7 ? (1U<<21) : 0U) | \
(0/!((UINT64_C(0##b)) & ~01111111111111111111111 ) ) | \
( 0 &sizeof&(b[(char*)0] )) \
\
)
void test()
{
enum{
MASK_A = B(1010), // 定数に使える.
MASK_ZERO = B(0000),
};
printf( "MASK_A==0x%x\n", MASK_A ); // MASK_A==0xa
printf( "MASK_ZERO==0x%x\n", MASK_ZERO ); // MASK_ZERO==0x0
enum{ ACCEPT_ONLY_ZERO_OR_ONE=B(1234) }; // コンパイルエラー
enum{ ACCEPT_NO_OPERATOR=B(1+0) }; // コンパイルエラー
assert( MASK_A==0b1010 ); // clang や gcc だと 0b につづけて2進数がかけるので、このマクロは不要。
}
怪しげな最後の二行が、B(1234)
や B(1+0)
をエラーにする。
しかし。C言語で &sizeof&
と書いたのは初めてだと思う。
投稿してから気づいたけど、BOOST_BINARY があるらしい。
see http://www.boost.org/doc/libs/1_53_0/libs/utility/utility.htm#BOOST_BINARY
ソースを見ると魔力の高さに畏れ入る。