78 lines
3.1 KiB
Plaintext
78 lines
3.1 KiB
Plaintext
== Why is this an issue?
|
|
|
|
The https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#left-shift-operator-[shifting] operators are used to do an https://en.wikipedia.org/wiki/Arithmetic_shift[arithmetic shift] to the bits of an https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types[integral numeric] value, either to the left or the right.
|
|
|
|
[source,csharp]
|
|
----
|
|
var number = 14; // ...01110 (14)
|
|
var left = number << 1; // ...11100 (28)
|
|
var right = number >> 1; // ...00111 (7)
|
|
----
|
|
|
|
Therefore, shifting an integral number by 0 is equivalent to doing nothing, since the bits do not move any positions to the left or the right.
|
|
|
|
On the other hand, shifting an integral number by a value greater than their count of bits minus one (`n_bits-1`) is equivalent to shifting by the value https://en.wikipedia.org/wiki/Modulo[modulo] the bit count of the number (`value % n_bits`).
|
|
|
|
In the case of `int` and `uint`, which take 32 bits in the memory, the shift count is given by the five low-order bits of the second operand, which can represent numbers from 0 to 31. This means that numbers having the same five low-order bits are treated the same by the shift operators.
|
|
|
|
[source,csharp]
|
|
----
|
|
var one = 0b0_00001;
|
|
var thirtyThree = 0b1_00001; // Same five low-order bits, 33 % 32 = 1
|
|
|
|
var shifted1 = 42 << one; // Results in 84
|
|
var shifted2 = 42 << thirtyThree; // Results in 84
|
|
----
|
|
|
|
Note that integral number with a less than 32-bit quantity (e.g. `short`, `ushort`) are implicitly converted to `int` before the shifting operation and so the rule for `int`/`uint` applies.
|
|
|
|
If the first operand is a `long` or `ulong` (64-bit quantity), the shift count is given by the six low-order bits of the second operand. That is, the actual shift count is 0 to 63 bits.
|
|
|
|
include::../exceptions.adoc[]
|
|
|
|
== How to fix it
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,csharp,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
short s = 1;
|
|
short shortShift1 = (short)(s << 0); // Noncompliant: the value does not change
|
|
short shortShift2 = (short)(s << 33); // Noncompliant: this is equivalent to shifting by 1
|
|
|
|
int i = 1;
|
|
int intShift = i << 33; // Noncompliant: this is equivalent to shifting by 1
|
|
|
|
long lg = 1;
|
|
long longShift1 = lg << 0; // Noncompliant: the value does not change
|
|
long longShift2 = lg << 65; // Noncompliant: this is equivalent to shifting by 1
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,csharp,diff-id=1,diff-type=compliant]
|
|
----
|
|
short s = 1;
|
|
short shortShift1 = s;
|
|
short shortShift2 = (short)(s << 1);
|
|
|
|
int i = 1;
|
|
var intShift = i << 1;
|
|
|
|
long lg = 1;
|
|
var longShift1 = lg;
|
|
var longShift2 = lg << 1;
|
|
----
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* Microsoft Learn - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#left-shift-operator-[Bitwise and shift operators (C# reference)]
|
|
* Wikipedia - https://en.wikipedia.org/wiki/Arithmetic_shift[Arithmetic shift]
|
|
* Wikipedia - https://en.wikipedia.org/wiki/Modulo[Modulo]
|
|
|
|
include::../rspecator.adoc[]
|