5

私は C プログラミングを学ぼうとしています。いくつかのソース コードを勉強していましたが、特にビット単位の演算子に関して、理解できないことがいくつかあります。これに関するいくつかのサイトを読んで、彼らが何をしているのかちょっとわかったのですが、戻ってこのコードを見てみると、なぜ、どこでどのように使用されているのか理解できませんでした.

私の最初の質問は、ビット単位の演算子ではなく、ASCII マジックに関するものです。

  1. 次のコードがどのように機能するかを誰かに説明してもらえますか?

    char a = 3;
    int x = a - '0';
    

    これはcharをintに変換するために行われることは理解していますが、その背後にあるロジックはわかりません。なぜ/どのように機能するのですか?

  2. さて、Bitwise演算子に関して、私はここで本当に迷っています。

    • このコードは何をしますか?

      if (~pointer->intX & (1 << i)) { c++; n = i; }
      

      ~ がビットを反転することをどこかで読みましたが、このステートメントが何をしているのか、なぜそれをしているのかわかりません。

      この行と同じ:

      row.data = ~(1 << i);
      
    • その他の質問:

      if (x != a)
        {
          ret |= ROW;
        }
      

      |= 演算子は正確には何をしているのでしょうか? 私が読んだことから、 |= は OR ですが、このステートメントが何をしているのかよくわかりません。

      このビット単位の演算子を使用しないように、このコードをわかりやすく書き直す方法はありますか? 私はそれらを理解するのが非常に混乱していると思うので、うまくいけば、誰かがそれらがどのように機能するかを理解するための正しい方向に私を向けてくれます!


ビット演算子についての理解が深まり、コード全体がより理解できるようになりました。

最後に 1 つ: このコードを理解しやすく、おそらく「ビットレベル」ではない方法で書き直すための「よりクリーンな」方法があるかどうかについて、誰も答えなかったようです。何か案は?

4

10 に答える 10

17

これによりジャンクが生成されます:

char a = 3; 
int x = a - '0';

これは異なります - 引用符に注意してください:

char a = '3'; 
int x = a - '0';

データ型にはchar、文字を識別する数値が格納されます。数字の 0 から 9 までの文字は、文字コード リストですべて隣り合っているので、「9」のコードから「0」のコードを引くと、答えは 9 になります。文字コードを桁の整数値に変換します。

(~pointer->intX & (1 << i))

ifそれがゼロでない場合、ステートメントによって true として解釈されます。3 つの異なるビット演算子が使用されています。

~ 演算子は数値のすべてのビットを反転するため、 だった場合pointer->intX01101010~pointer->intXなります10010101。(全体を通して、バイトの内容を示していることに注意してください。32 ビット整数の場合、32 桁の 1 と 0 を書き込む必要があります)。

& 演算子は、各ビットを個別に処理することにより、2 つの数値を 1 つの数値に結合します。結果のビットは、両方の入力ビットが 1 の場合にのみ 1 になります。したがって、左側が00101001で右側が00001011の場合、結果は になります00001001

最後に、<<左シフトを意味します。00000001 から始めて 3 桁左にシフトすると、00001000 になります。したがって、式 (1 << i) は、ビット i がオンになり、他のビットがすべてオフになる値を生成します。

すべてをまとめると、 でビットiがオフ (ゼロ) になっているかどうかをテストしpointer->intXます。

したがって、何が機能するかを理解できるかもしれ~(1 << i)ません。である場合、括弧内のものは になりi、全体が になります。40001000011101111

ret |= ROW;

それは次と同等です:

ret = ret | ROW;

|演算子は、入力ビットの&いずれかが の場合に結果のビットが 1 であることを除いて、同様です1。したがって、retis00100000ROWis00000010の場合、結果は になります00100010

于 2009-03-24T19:27:37.780 に答える
0

1)次のコードがどのように機能するかを誰かに説明してもらえますか?文字 a = 3; int x = a - '0'; これはcharをintに変換するために行われることは理解していますが、その背後にあるロジックはわかりません。なぜ/どのように機能するのですか?

もちろん。変数aは char 型であり、0 を一重引用符で囲むと、C もそれを char として表示します。最後に、 xが整数として定義されているため、ステートメント全体が自動的に対応する整数に型キャストされます。

2) さて、Bitwise 演算子に関して、私はここで本当に迷っています。--- このコードは何をしますか? if (~pointer->intX & (1 << i)) { c++; n = 私; ~ がビットを反転することをどこかで読みましたが、このステートメントが何をしているのか、なぜそうしているのかわかりません。

(~pointer->intX & (1 << i)) is saying:

intX を否定し、i ビット左にシフトされた 1 と AND します。

したがって、intX = 1011、i = 2 の場合、得られるものは次のようになります。

(0100 & 0100) 

-negate 1011 = 0100

-(1 << 2) = 0100

0100 & 0100 = 1 :)

次に、AND 演算が 1 を返した場合 (私の例ではそうです) { c++; n = 私; }

したがって、c を 1 増やし、変数 n を i に設定します。

次の行も同様です: row.data = ~(1 << i);

Same principle here.
Shift a 1 to the left by i places, and negate.

So, if i = 2 again

(1 << 2) = 0100

~(0100) = 1011

** - - その他の質問:

if (x != a) { ret |= ROW; }

|= 演算子は正確には何をしているのでしょうか? 私が読んだことから、|= は OR ですが、このステートメントが何をしているのかよくわかりません。**

if (x != a) (うまくいけば、これはあなたには明らかです....変数 x が変数 a と等しくない場合)

ret |= ROW;

equates to

ret = ret | ROW;

つまり、ROW を使用したバイナリ OR ret

AND 演算と OR 演算の正確な例については、バイナリ ロジックを十分に理解している必要があります。

ウィキペディアで真理値表を確認してください...つまり

ビット演算

于 2009-03-24T19:36:18.837 に答える
0

char a = 3; int x = a - '0';私はあなたが意味したと思いますchar a = '3'; int x = a - '0';。ASCII では数字が '0'、'1'、'2'、... のように順番に並んでいることを理解すれば、理解するのは簡単です。 ' - '0' は 1 です。

ビット単位の操作の場合、ビットを見始めるまで把握するのは困難です。これらの演算を 2 進数で表示すると、それらがどのように機能するかを正確に確認できます...

010 & 111 = 010
010 | 111 = 111
010 ^ 111 = 101
~010 = 101
于 2009-03-24T19:27:20.887 に答える
0

おそらくタイプミスがあると思います。意味は次のとおりです。

char a = '3';

これが機能する理由は、すべての数字が順番に並んでいて、「0」が最初だからです。明らかに、'0' - '0' = 0.'1' - '0' = 1 です。これは、'1' の文字値が '0' の文字値よりも 1 大きいためです。等。

于 2009-03-24T19:27:33.663 に答える
0

1) char は実際には単なる 8 ビット整数です。'0' == 48、およびそれが意味するすべて。

2) (~(pointer->intX) & (1 << i)) は、ポインターが指す intX メンバーの (右から) 'i' 番目のビットが設定されていないかどうかを評価します。~ はビットを反転するため、すべての 0 が 1 になり、その逆も同様です。次に、 1 << i は目的の場所に 1 を 1 つ置き、& は目的のビットのみが保持されるように 2 つの値を結合し、全体が評価されます。そのビットが最初から 0 だった場合は true になります。

3) | ビット単位の or です。両方のオペランドの各ビットを取得し、論理 OR を実行して、いずれかのオペランドにそのビットが設定されている場合に各ビットが設定される結果を生成します。0b11000000 | 0b00000011 == 0b11000011. |= は代入演算子で、a+=b は a=a+b を意味し、a|=b は a=a|b を意味します。

ビット単位の演算子を使用しないと、場合によっては読みやすくなりますが、通常、強力なコンパイラの最適化を行わないと、コードが大幅に遅くなります。

于 2009-03-24T19:28:30.963 に答える
0

あなたが参照している減算のトリックは、ASCII 番号がゼロから始まる昇順で配置されているため機能します。したがって、ASCII '0' が 48 の値である場合 (実際にそうです)、'1' は 49 の値、'2' は 50 などです。したがって、ASCII('1') - ASCII('0') = 49 - 48 = 1。

ビット単位の演算子に関する限り、変数に対してビットレベルの操作を実行できます。

あなたの例を分解しましょう:

(1 << i)-- これは、定数 1 を i ビット左シフトしています。したがって、i=0 の場合、結果は 10 進数の 1 になります。i = 1 の場合、ビットを 1 つ左にシフトし、ゼロを埋め戻して、2 進数の 0010 または 10 進数の 2 を生成します。i = 2 の場合、ビット 2 を左、ゼロで埋め戻し、2 進数の 0100 または 10 進数の 4 などを生成します。

~pointer->intX-- これは、ポインターの intX メンバーの値を取得し、そのビットを反転して、すべてのゼロを 1 に、またはその逆に設定します。

&-- アンパサンド演算子は、ビットごとの AND 比較を行います。この結果は、式の左辺と右辺の両方が 1 の場合は 1 になり、それ以外の場合は 0 になります。

したがって、pointer->intX右から i 番目の位置に 0 ビットがあれば、テストは成功します。

また、|=ビットごとの OR 比較を行い、結果を式の左側に代入することを意味します。ビットごとの OR の結果は、対応する左側または右側のビットが 1 であるすべてのビットに対して 1 です。

于 2009-03-24T19:28:41.023 に答える