LoginSignup
11
9

More than 5 years have passed since last update.

C言語の2進数マクロ

Last updated at Posted at 2013-06-02

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
ソースを見ると魔力の高さに畏れ入る。

11
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9