私はcでこのようなことをしたいと頻繁に望んでいます:
val1 &= 0b00001111; //clear high nibble
val2 |= 0b01000000; //set bit 7
val3 &= ~0b00010000; //clear bit 5
この構文を持つことは、Cに信じられないほど便利な追加機能のように思えますが、欠点はありません。また、ビット調整がかなり一般的な低レベル言語にとっては自然なことのようです。
編集:私はいくつかの他の素晴らしい選択肢を見ていますが、より複雑なマスクがある場合、それらはすべてバラバラになります。たとえば、reg
がマイクロコントローラのI/Oピンを制御するレジスタであり、ピン2、3、および7を同時にハイに設定したい場合、reg = 0x46;
と書くことができますが、それについて考えて10秒を費やさなければなりませんでした(そして、1日か2日それを見なかった後にそれらのコードを読むたびに10秒を再び費やす必要があります)または私はreg = (1 << 1) | (1 << 2) | (1 << 6);
を書くことができましたが、個人的にこれは単に「reg = 0b01000110;」と書くよりも明確ではないと思います。ただし、8ビットまたは16ビットのアーキテクチャを超えて拡張できないことに同意できます。 32ビットのマスクを作成する必要があったわけではありません。
国際標準の理論的根拠-プログラミング言語C §6.4.4.1整数定数
バイナリ定数を追加するという提案は、前例の欠如と不十分なユーティリティのために拒否されました。
これは標準Cではありませんが、GCCは0b
または0B
で始まる拡張機能としてサポートしています。
i = 0b101010;
詳細については here をご覧ください。
これが hexadecimal を... 16進数にプッシュしたものです。 「...16進表記の主な用途は、コンピューティングおよびデジタルエレクトロニクスにおけるバイナリコード値の人間に優しい表現です...」。次のようになります。
val1 |= 0xF;
val2 &= 0x40;
val3 |= ~0x10;
16進数:
ある程度練習すれば、16進数と2進数の間の変換はより自然になります。オンラインのbin/hex表記コンバーターを使用せずに、手動で変換を書き出してみてください。数日後には自然になります(結果としてより高速になります)。
Aside:バイナリリテラルはC標準ではありませんが、GCCでコンパイルする場合、バイナリリテラルを使用することができます。 'または' 0B '。詳細については、公式ドキュメント here を参照してください。例:
int b1 = 0b1001; // => 9
int b2 = 0B1001; // => 9
すべての例はさらに明確に記述できます。
val1 &= (1 << 4) - 1; //clear high nibble
val2 |= (1 << 6); //set bit 6
val3 &=~(1 << 3); //clear bit 3
(私は、自然が意図したように、コメントをゼロからカウントするように修正する自由を取りました。)
コンパイラはこれらの定数を折りたたみますので、このように記述することによるパフォーマンスの低下はありません。そして、これらは0b...
バージョンよりも読みやすいです。
読みやすさが第一の関心事だと思います。低レベルではありますが、マシンではなくコードを読んで保守するのは人間です。
0b1000000000000000000000000000000(0x40000000)
を誤って入力したことを理解するのは簡単ですか?本当にあなたは0b10000000000000000000000000000000(0x80000000)
を意味しますか?
「たとえば、regがマイクロコントローラーのI/Oピンを制御するレジスタである場合」
これは悪い例だと思わずにはいられません。制御レジスタのビットには特定の機能があります(個々のIOビット)に接続されているデバイスと同様)。
コード内のバイナリを計算するよりも、ヘッダーファイルのビットパターンに記号定数を提供する方がはるかに賢明です。バイナリを16進数または8進数に変換するのは簡単です。01000110をIOレジスタに書き込むとどうなるかを覚えておいてください。特にデータシートや回路図が手元にない場合はそうです。
その後、バイナリコードを解決しようとする10秒間を節約するだけでなく、それが何をするのかを試行するのに多少時間がかかるかもしれません。