1. 最初の質問。
この記事を開始する前に、最初のウェブマスターインタビューの数日前に与えられ、面接官C言語の巨人は質問を与えた:
int i = 255;
i <<= 24;
i >>= 24;
** 質問:**
- 最终
i等于多少? - 如果
i是uint类型,最终i结果是多少?
2. C#ビット操作
C#ビット演算は、バイナリデータとビット演算を処理する際に重要な役割を果たす強力なツールです。ビット演算子を使用することで、ビット&、ビットOR、ビット例外、ビット反転などのビットレベルの整数演算を行うことができます。ビット演算は、パフォーマンスの最適化、データの圧縮、ビットマスクとビットフラグの実装などに使用できます。C#ビット演算の基本原理と一般的なユースケースを理解し、習得することで、バイナリデータをより効率的に処理し、場合によってはコードのパフォーマンスと可読性を向上させることができます。C#ビット演算を深く理解することで、プログラミングの創造性と柔軟性を高めることができます。
本节内容主要参考文章:C# 中使用位运算(与、或、非 & | ^)进行数据校验和c# 位运算符_c#位运算符-CSDN博客。
ビット演算を学ぶには、まずビット演算とは何かを理解する必要があります。プログラム内のすべての内容は、コンピュータのメモリにバイナリ形式(すなわち、0または1)で格納され、ビット演算は、メモリ内の各バイナリに対して直接演算操作を行うことです。
C#では、整数オペランドはビット単位で論理演算を行うことができる。ビットによる論理演算の意味は、被演算対象の各ビットを順次取って論理演算を行い、各ビットの論理演算結果は結果値の各ビットになるということです。C#でサポートされるビット論理演算子を表に示す。
| オペレーショナルシンボル | 意味がある。 | オペランド·タイプ | 演算結果のタイプ | オブジェクトの数 | 例:例 | |
|---|---|---|---|---|---|---|
| ~ | ビット論理 *非 演算、ビット単位で逆を取る | 整数型、文字型 | 整数型です | 1 | ~a | |
| & | ビット論理 ** と ** 演算は、実際には&&論理演算子と一致します。 | 同上。 | 同上。 | 2 | a & b | |
| | | ビット論理 ** または ** 演算、\と同様 | |似たような場所 | 同上。 | 同上。 | 2 | a | b |
| ^ | ビット論理 ** 例外または ** 演算 | 同上。 | 同上。 | 2 | a ^ b | |
| << | * **左シフト ** | 同上。 | 同上。 | 2 | a<<4 | |
| >> | ビット ***右シフト ** | 同上。 | 同上。 | 2 | a>>2 |
2.1. ~:ビット非演算
ビット論理非演算は単一目的であり、オペランドは1つしかない。ビット論理非演算オペランドの値をビット単位で非演算します。つまり、ビットが0に等しい場合は1に変換し、ビットが1に等しい場合は0に変換します。
例えば、バイナリ10010001に対してビット論理非演算を行うと、結果は0 11011 10に等しくなり、10進数では次のようになります。
145は110に等しい;バイナリの010101をビット論理的に非演算すると、結果は10101010に等しい。10進数では85 = 176です。
int a = 1001 0001; // 十进制:145
int b = ~a; // b = 0110 1110,即十进制:110
来复杂的,看这篇文章c# 位运算符_c#位运算符-CSDN博客:
int a = 13;
int b = -14;
Console.WriteLine(~a); // -14
Console.WriteLine(~b); // 13;
これを行うには、まずいくつかの原則を覚えておく必要があります。
| オリジナルコード※ | アンチコードコード | 補遺 ** | 反を取る。 | |
|---|---|---|---|---|
| 正の数 | 符号ビット+絶対値 | オリジナルコード。 | オリジナルコード。 | 0と1の交換 |
| 13 | 0 1101 | 0 1101 | 0 1101 | 1 0010 |
| 負の数 | 符号ビット+絶対値 | 絶対値は逆。 | アンチコード+1 | 0と1の交換 |
| -14 | 1 1110 | 1 0001 | 1 0010 | 0 1101 |
*:符号ビットの長さは型定義に依存し、C#ではintの符号ビットは1ビットである。 **:C#の値は補数として格納される
以下は、2つのコード間の変換方法です。
int b = 1 1110; // 前面的1表示符号位
反码 = 1 0001; // 符号位不变
补码 = 1 0010; // 反码加1
补码取反 = 0 1101; // 得到新的反码就是结果a,连同符号位一起反)
int a = 0 1101;
a的补码 = 0 1101;
补码取反 = 1 0010; // 此时为b的补码了
补码转反码 = 1 0001; // 即减1
反码转原码 = 1 1110; // 就是结果b的源码
多くの実験の結果、1つのルールがあります。
~+a =-a+1;正の数をビット単位で反転させるだけで、現在の数に1を加算して負に変更できます
~-a = + a-1
2.2. $:ビット論理と操作
ビット論理和演算は、2つのオペランドをビット単位で和演算します。AND演算の規則:1と1は1に等しく、1と0は0に等しい。
サンプルコード:
int a = 13;
int b = 14;
int result = a & b; // 12
Binaryに変換:
int a = 0000 1101;
int b = 0000 1110;
int result = 0000 1100;
&演算子は、バイナリの同じ位置の0と1を比較し、同じ位置の数値が同じ場合は同じ数値を返し、そうでなければ0を返します。&&演算子は、2つのboolが一致する場合はTrueを返し、そうでなければFalseを返します。結果は10進数で12に変換されます。
2.3. |論理または操作。
ビットOR演算は、2つのオペランドをビットごとにOR演算します。OR演算のルールは、1または1など1、1または0は1に等しい。
サンプルコード:
int a = 13;
int b = 14;
int result = a | b; // 15
Binaryに変換:
int a = 0000 1101;
int b = 0000 1110;
int result = 0000 1111;
実際には、判断方法は同じですが、結果が異なるだけです。|演算子は、2つのバイナリの同じ位置の0と1を判断し、いずれかの位置の数値が1である限り1を返します。||演算子も同様で、Trueがある限りTrueを返し、結果を10進数で15に変換します。
2.4. ^:ビット論理排他的OR演算
ビット論理排他的和演算は、2つのオペランドをビット単位で排他的和演算します。例外和演算の法則は、1例外または1は0に等しい。
1异または0は1に等しく、0异または0は0に等しい。つまり、同じ0、異なる1です。
サンプルコード:
int a = 13;
int b = 14;
int result = a ^ b; // 3
Binaryに変換:
int a = 0000 1101;
int b = 0000 1110;
int result = 0000 0011;
同じ位置の上の数字を判断する場合、2つの数字が同じなら0でも1でも0を返し、どちらか一方が1なら1を返すことがわかります。そして、|位置の1つが1であれば1を返すので、名前は異和(異なる戻り和)という。
2.5. <<:左シフト操作
位左移运算将整个数按位左移若干位,左移后空出的部分0。比如:8位的byte型变量byte a=0x65(即二进制的01100101),将其左移3位:a<<3的结果是0x27(即二进制的00101000)。
byte a = 0110 0101;
a <<= 3;//0010 1000
最初のオペランドを2番目のオペランドで指定された桁数だけ左に移動し、空いた位置に0を挿入します。 左移動は乗算に相当する。左に1桁シフトすると2乗、左に2桁シフトすると4乗、左に3桁シフトすると8乗になります。
x<<1= x*2
x<<2= x*4
x<<3= x*8
x<<4= x*16
2.6. >>右シフト演算
位右移运算将整个数按位右移若干位,右移后空出的部分填0。比如:8位的byte型变量byte a=0x65(既(二进制的01100101))将其右移3位:a>>3的结果是0x0c(二进制00001100)。
byte a = 0110 0101;
a >>= 3;//0000 1100
最初のオペランドを2番目のオペランドで指定されたビット数だけ右に移動し、空いた位置に0を挿入します。
右シフトは除算に等しい。右に1桁シフトすると2で割ること、右に2桁シフトすると4で割ること、右に3桁シフトすると8で割ることができます。
x>>1= x/2
x>>2= x/4
x>>3= x/8
x>>4= x/16
3. 概要と質問への回答
看微软文档位运算符和移位运算符两点注意
- 位运算和移位运算永远不会导致溢出,并且不会在已检查和未检查的上下文中产生相同的结果。
- 移位运算符仅针对
int、uint、long和ulong类型定义,因此运算的结果始终包含至少 32 位。如果左侧操作数是其他整数类型(sbyte、byte、short、ushort或char),则其值将转换为int类型。
ここでは、最初の質問とその答えを説明します。
int i = 255; // 00000000 00000000 00000000 11111111
i <<= 24; // 11111111 00000000 00000000 00000000
i >>= 24; // 11111111 11111111 11111111 11111111;
修改i数据类型为uint:
uint i = 255; // 00000000 00000000 00000000 11111111
i <<= 24; // 11111111 00000000 00000000 00000000
i >>= 24; // 00000000 00000000 00000000 11111111;
int和uint位移后结果不同的原因:
- 符号付き整数の右シフト操作では、最上位の符号ビットも右シフトされます。つまり、元の値の最上位ビットが1の場合、右シフト後も符号ビットは保持され、1がパディングされます。このような右シフト操作は算術右シフトと呼ばれる。
- 符号なし整数の右シフト操作では、符号ビットは保持されず、最上位ビットの0も右シフトされます。このような右シフト操作は論理右シフトと呼ばれる。
** この記事に誤りがある場合は、訂正を歓迎します。