47

私はよく、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 ビット マスクを作成する必要があったわけではありません。

4

9 に答える 9

52

Rationale for International Standard - Programming Languages C §6.4.4.1整数定数によると

バイナリ定数を追加する提案は、先例がなく、実用性が不十分であるため、却下されました。

標準の C にはありませんが、GCC は拡張機能としてサポートしており、接頭辞は0bor0Bです。

 i = 0b101010;

詳しくはこちらをご覧ください。

于 2013-08-15T01:06:40.747 に答える
21

これが、 16 進数を16 進数に押し上げたものです。「... 16 進表記の主な用途は、コンピューティングおよびデジタル エレクトロニクスにおけるバイナリ コード値の人間にやさしい表現です ... ". 次のようになります。

val1 |= 0xF;
val2 &= 0x40;
val3 |= ~0x10;

16 進数:

  1. 1 桁の 16 進数でニブル (4 ビットまたは 8 進数の半分) を表すことができます。
  2. 2 つの 16 進数で 1 バイト (8 ビット) を表すことができます。
  3. 大きなマスクにスケーリングすると、16 進数ははるかにコンパクトになります。

ある程度練習すれば、16 進数と 2 進数の間の変換がより自然になります。オンラインの bin/hex 表記コンバーターを使用せずに、変換を手で書き出すようにしてください。そうすれば、数日で自然になります (結果としてより速くなります)。

余談:バイナリ リテラルは C 標準ではありませんが、GCC でコンパイルする場合は、バイナリ リテラルを使用できます。プレフィックスとして '0b' または '0B' を付ける必要があります。詳細については、こちらの公式ドキュメントを参照してください。例:

int b1 = 0b1001; // => 9
int b2 = 0B1001; // => 9
于 2013-08-15T01:01:09.817 に答える
15

All of your examples can be written even more clearly:

val1 &= (1 << 4) - 1; //clear high nibble
val2 |= (1 << 6); //set bit 6
val3 &=~(1 << 3); //clear bit 3

(I have taken the liberty of fixing the comments to count from zero, like Nature intended.)

Your compiler will fold these constants, so there is no performance penalty to writing them this way. And these are easier to read than the 0b... versions.

于 2013-08-15T01:15:14.263 に答える
11

読みやすさが第一だと思います。低レベルではありますが、コードを読んで維持するのは人間であり、機械ではありません。

0b1000000000000000000000000000000(0x40000000)間違って入力したことが、本当はどこにあるのか、簡単にわかります0b10000000000000000000000000000000(0x80000000)か?

于 2013-08-15T01:18:24.300 に答える
3

「たとえば、reg がマイクロコントローラの I/O ピンを制御するレジスタである場合」

これは悪い例だと思わざるを得ません。制御レジスタのビットには特定の機能があります (個々の IO ビットに接続されたデバイスと同様)。

コード内でバイナリを処理するよりも、ヘッダー ファイルでビット パターンの記号定数を提供する方がはるかに賢明です。2 進数を 16 進数または 8 進数に変換するのは簡単ですが、01000110 を IO レジスタに書き込むと何が起こるかを覚えておく必要はありません。特にデータシートや回路図が手元にない場合はそうではありません。

そうすれば、バイナリ コードを理解するのにかかる 10 秒を節約できるだけでなく、それが何をするのかを理解するのに多少長い時間がかかるかもしれません!

于 2015-08-14T10:51:32.173 に答える
0

Binary は、コントローラーで特定の出力を設定する場合に最も役立ちます。私は技術的に違法なハックを使用していますが、それでも常に機能します。LED をオンにする必要があるだけの場合、ジョブに int 全体または char を使用することは、あらゆる感​​性を損ないます。忘れないでほしいのは、おそらく、これらのコンパイルの洗練度の究極について話しているわけではないということです。したがって、グループ制御と組み合わせた個々の理解度のために、ビットフィールドを使用します:-

struct DEMAND
{
    unsigned int dOil   :   1; // oil on
    unsigned int dAir   :   1; // air on
    unsigned int dHeat  :   1; // heater on
    unsigned int dMtr1  :   1; // motor 1 on
    unsigned int dMtr2  :   1; // motor 2 on
    unsigned int dPad1  :   10;// spare demand o/p's
    unsigned int dRunCycle: 1; // GO !!!!
    unsigned int dPad2  :   15;// spare o/p's
    unsigned int dPowerOn:  1; // Power on
}DemandBF;

それらは、単独で使用すると簡単に対処できます。または、より完全な制御のために、K&R を無視して unsigned int として扱うことができます:-

void *bitfPt = &DemandBF;
unsigned int *GroupOuts = (unsigned int *)bitfPt;

DemandBF.dAir = 1;   // Clearly describes what's turning on
DemandBF.dPowerOn = 1;

*GroupOuts ^= 0x04; // toggle the heater

*GroupOuts = 0; // kill it all

それは常に私にとってはうまくいきました。おそらく移植性はありませんが、とにかくこのようなものを実際に移植するのは誰ですか? 試してごらん。

于 2019-02-19T23:56:29.043 に答える
-2

以下は 8 ビットに制限されていますが、簡単に拡張できます。C リテラルにはなりませんが、コンパイル時定数になります。

#define B_(X) B8_("00000000" #X)
#define B8_(X) B8__(X+sizeof(X)-9)
#define B8__(X) \
        (B___((X), 7) | B___((X), 6) | B___((X), 5) | B___((X), 4) | \
         B___((X), 3) | B___((X), 2) | B___((X), 1) | B___((X), 0))
#define B___(X, I) (((X)[7-(I)] - '0') << (I))

次の関数は、定数を返すコードにコンパイルされます18

int test(void) {
    return B_(10010);
}

オンラインでお試しください!

パフォーマンスが問題にならない場合は、もっと簡単なことを行うことができます。

#define B_(x) strtoull(#x, 0, 2)
于 2013-08-15T02:07:54.187 に答える