Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Download Microsoft EdgeMore info about Internet Explorer and Microsoft Edge
Table of contentsExit focus mode

Bitwise and shift operators (C# reference)

  • 2025-06-11
Feedback

In this article

The bitwise and shift operators include unary bitwise complement, binary left and right shift, unsigned right shift, and the binary logical AND, OR, and exclusive OR operators. These operands take operands of theintegral numeric types or thechar type.

Those operators are defined for theint,uint,long,ulong,nint, andnuint types. When both operands are of other integral types (sbyte,byte,short,ushort, orchar), their values are converted to theint type, which is also the result type of an operation. When operands are of different integral types, their values are converted to the closest containing integral type. For more information, see theNumeric promotions section of theC# language specification. The compound operators (such as>>=) don't convert their arguments toint or have the result type asint.

The&,|, and^ operators are also defined for operands of thebool type. For more information, seeBoolean logical operators.

Bitwise and shift operations never cause overflow and produce the same results inchecked and unchecked contexts.

Bitwise complement operator ~

The~ operator produces a bitwise complement of its operand by reversing each bit:

uint a = 0b_0000_1111_0000_1111_0000_1111_0000_1100;uint b = ~a;Console.WriteLine(Convert.ToString(b, toBase: 2));// Output:// 11110000111100001111000011110011

You can also use the~ symbol to declare finalizers. For more information, seeFinalizers.

Left-shift operator <<

The<< operator shifts its left-hand operand left by the number of bits defined by its right-hand operand. For information about how the right-hand operand defines the shift count, see theShift count of the shift operators section.

The left-shift operation discards the high-order bits that are outside the range of the result type and sets the low-order empty bit positions to zero, as the following example shows:

uint x = 0b_1100_1001_0000_0000_0000_0000_0001_0001;Console.WriteLine($"Before: {Convert.ToString(x, toBase: 2)}");uint y = x << 4;Console.WriteLine($"After:  {Convert.ToString(y, toBase: 2)}");// Output:// Before: 11001001000000000000000000010001// After:  10010000000000000000000100010000

Because the shift operators are defined only for theint,uint,long, andulong types, the result of an operation always contains at least 32 bits. If the left-hand operand is of another integral type (sbyte,byte,short,ushort, orchar), its value is converted to theint type, as the following example shows:

byte a = 0b_1111_0001;var b = a << 8;Console.WriteLine(b.GetType());Console.WriteLine($"Shifted byte: {Convert.ToString(b, toBase: 2)}");// Output:// System.Int32// Shifted byte: 1111000100000000

Right-shift operator >>

The>> operator shifts its left-hand operand right by the number of bits defined by its right-hand operand. For information about how the right-hand operand defines the shift count, see theShift count of the shift operators section.

The right-shift operation discards the low-order bits, as the following example shows:

uint x = 0b_1001;Console.WriteLine($"Before: {Convert.ToString(x, toBase: 2), 4}");uint y = x >> 2;Console.WriteLine($"After:  {Convert.ToString(y, toBase: 2).PadLeft(4, '0'), 4}");// Output:// Before: 1001// After:  0010

The high-order empty bit positions are set based on the type of the left-hand operand as follows:

  • If the left-hand operand is of typeint orlong, the right-shift operator performs anarithmetic shift: the value of the most significant bit (the sign bit) of the left-hand operand is propagated to the high-order empty bit positions. That is, the high-order empty bit positions are set to zero if the left-hand operand is non-negative and set to one if it's negative.

    int a = int.MinValue;Console.WriteLine($"Before: {Convert.ToString(a, toBase: 2)}");int b = a >> 3;Console.WriteLine($"After:  {Convert.ToString(b, toBase: 2)}");// Output:// Before: 10000000000000000000000000000000// After:  11110000000000000000000000000000
  • If the left-hand operand is of typeuint orulong, the right-shift operator performs alogical shift: the high-order empty bit positions are always set to zero.

    uint c = 0b_1000_0000_0000_0000_0000_0000_0000_0000;Console.WriteLine($"Before: {Convert.ToString(c, toBase: 2), 32}");uint d = c >> 3;Console.WriteLine($"After:  {Convert.ToString(d, toBase: 2).PadLeft(32, '0'), 32}");// Output:// Before: 10000000000000000000000000000000// After:  00010000000000000000000000000000

Note

Use theunsigned right-shift operator to perform alogical shift on operands of signed integer types. The logical shift is preferred to casting a left-hand operand to an unsigned type and then casting the result of a shift operation back to a signed type.

Unsigned right-shift operator >>>

Available in C# 11 and later, the>>> operator shifts its left-hand operand right by the number of bits defined by its right-hand operand. For information about how the right-hand operand defines the shift count, see theShift count of the shift operators section.

The>>> operator always performs alogical shift. That is, the high-order empty bit positions are always set to zero, regardless of the type of the left-hand operand. The>> operator performs anarithmetic shift (that is, the value of the most significant bit is propagated to the high-order empty bit positions) if the left-hand operand is of a signed type. The following example demonstrates the difference between>> and>>> operators for a negative left-hand operand:

int x = -8;Console.WriteLine($"Before:    {x,11}, hex: {x,8:x}, binary: {Convert.ToString(x, toBase: 2), 32}");int y = x >> 2;Console.WriteLine($"After  >>: {y,11}, hex: {y,8:x}, binary: {Convert.ToString(y, toBase: 2), 32}");int z = x >>> 2;Console.WriteLine($"After >>>: {z,11}, hex: {z,8:x}, binary: {Convert.ToString(z, toBase: 2).PadLeft(32, '0'), 32}");// Output:// Before:             -8, hex: fffffff8, binary: 11111111111111111111111111111000// After  >>:          -2, hex: fffffffe, binary: 11111111111111111111111111111110// After >>>:  1073741822, hex: 3ffffffe, binary: 00111111111111111111111111111110

Logical AND operator &

The& operator computes the bitwise logical AND of its integral operands:

uint a = 0b_1111_1000;uint b = 0b_1001_1101;uint c = a & b;Console.WriteLine(Convert.ToString(c, toBase: 2));// Output:// 10011000

Forbool operands, the& operator computes thelogical AND of its operands. The unary& operator is theaddress-of operator.

Logical exclusive OR operator ^

The^ operator computes the bitwise logical exclusive OR, also known as the bitwise logical XOR, of its integral operands:

uint a = 0b_1111_1000;uint b = 0b_0001_1100;uint c = a ^ b;Console.WriteLine(Convert.ToString(c, toBase: 2));// Output:// 11100100

Forbool operands, the^ operator computes thelogical exclusive OR of its operands.

Logical OR operator |

The| operator computes the bitwise logical OR of its integral operands:

uint a = 0b_1010_0000;uint b = 0b_1001_0001;uint c = a | b;Console.WriteLine(Convert.ToString(c, toBase: 2));// Output:// 10110001

Forbool operands, the| operator computes thelogical OR of its operands.

Compound assignment

For a binary operatorop, a compound assignment expression of the form

x op= y

Is equivalent to

x = x op y

Except thatx is only evaluated once.

The following example demonstrates the usage of compound assignment with bitwise and shift operators:

uint INITIAL_VALUE = 0b_1111_1000;uint a = INITIAL_VALUE;a &= 0b_1001_1101; Display(a);  // output: 10011000a = INITIAL_VALUE;a |= 0b_0011_0001; Display(a);  // output: 11111001a = INITIAL_VALUE;a ^= 0b_1000_0000;Display(a);  // output: 01111000a = INITIAL_VALUE;a <<= 2;Display(a);  // output: 1111100000a = INITIAL_VALUE;a >>= 4;Display(a);  // output: 00001111a = INITIAL_VALUE;a >>>= 4;Display(a);  // output: 00001111void Display(uint x) => Console.WriteLine($"{Convert.ToString(x, toBase: 2).PadLeft(8, '0'), 8}");

Because ofnumeric promotions, the result of theop operation might be not implicitly convertible to the typeT ofx. In such a case, ifop is a predefined operator and the result of the operation is explicitly convertible to the typeT ofx, a compound assignment expression of the formx op= y is equivalent tox = (T)(x op y), except thatx is only evaluated once. The following example demonstrates that behavior:

byte x = 0b_1111_0001;int b = x << 8;Console.WriteLine($"{Convert.ToString(b, toBase: 2)}");  // output: 1111000100000000x <<= 8;Console.WriteLine(x);  // output: 0

Operator precedence

The following list orders bitwise and shift operators starting from the highest precedence to the lowest:

  • Bitwise complement operator~
  • Shift operators<<,>>, and>>>
  • Logical AND operator&
  • Logical exclusive OR operator^
  • Logical OR operator|

Use parentheses,(), to change the order of evaluation imposed by operator precedence:

uint a = 0b_1101;uint b = 0b_1001;uint c = 0b_1010;uint d1 = a | b & c;Display(d1);  // output: 1101uint d2 = (a | b) & c;Display(d2);  // output: 1000void Display(uint x) => Console.WriteLine($"{Convert.ToString(x, toBase: 2), 4}");

For the complete list of C# operators ordered by precedence level, see theOperator precedence section of theC# operators article.

Shift count of the shift operators

For thex << count,x >> count, andx >>> count expressions, the actual shift count depends on the type ofx as follows:

  • If the type ofx isint oruint, the low-orderfive bits of the right-hand operand define the shift count. That is, the shift count is computed fromcount & 0x1F (orcount & 0b_1_1111).

  • If the type ofx islong orulong, the low-ordersix bits of the right-hand operand define the shift count. That is, the shift count is computed fromcount & 0x3F (orcount & 0b_11_1111).

The following example demonstrates that behavior:

int count1 = 0b_0000_0001;int count2 = 0b_1110_0001;int a = 0b_0001;Console.WriteLine($"{a} << {count1} is {a << count1}; {a} << {count2} is {a << count2}");// Output:// 1 << 1 is 2; 1 << 225 is 2int b = 0b_0100;Console.WriteLine($"{b} >> {count1} is {b >> count1}; {b} >> {count2} is {b >> count2}");// Output:// 4 >> 1 is 2; 4 >> 225 is 2int count = -31;int c = 0b_0001;Console.WriteLine($"{c} << {count} is {c << count}");// Output:// 1 << -31 is 2

Note

As the preceding example shows, the result of a shift operation can be non-zero even if the value of the right-hand operand is greater than the number of bits in the left-hand operand.

Enumeration logical operators

Everyenumeration type supports the~,&,|, and^ operators. For operands of the same enumeration type, a logical operation is performed on the corresponding values of the underlying integral type. For example, for anyx andy of an enumeration typeT with an underlying typeU, thex & y expression produces the same result as the(T)((U)x & (U)y) expression.

You typically use bitwise logical operators with an enumeration type that is defined with theFlags attribute. For more information, see theEnumeration types as bit flags section of theEnumeration types article.

Operator overloadability

A user-defined type canoverload the~,<<,>>,>>>,&,|, and^ operators. When a binary operator is overloaded, the corresponding compound assignment operator is also implicitly overloaded. Beginning with C# 14, a user-defined type can explicitly overload the compound assignment operators to provide a more efficient implementation. Typically, a type overloads these operators because the value can be updated in place, rather than allocating a new instance to store the result of the binary operation. If a type doesn't provide an explicit overload, the compiler generates the implicit overload.

If a user-defined typeT overloads the<<,>>, or>>> operator, the type of the left-hand operand must beT. In C# 10 and earlier, the type of the right-hand operand must beint; beginning with C# 11, the type of the right-hand operand of an overloaded shift operator can be any.

C# language specification

For more information, see the following sections of theC# language specification:

See also

Collaborate with us on GitHub
The source for this content can be found on GitHub, where you can also create and review issues and pull requests. For more information, seeour contributor guide.

Feedback

Was this page helpful?

YesNo

In this article

Was this page helpful?

YesNo