为什么 C# 中的 32 位移位 return 它最初移位的值?

Why would a 32 bit shift in C# return the value it was originally shifting?

我只是想就 C# 位移位寻求一些说明。

当我将 UINT32 的位向右移动 32 位时,我将值移回。我的预期结果是将值清零 00000000

例如:

System.Diagnostics.Debug.WriteLine((Convert.ToUInt32("FFFFFFFF", 16) >> 8).ToString("X8"));
System.Diagnostics.Debug.WriteLine((Convert.ToUInt32("FFFFFFFF", 16) >> 16).ToString("X8"));
System.Diagnostics.Debug.WriteLine((Convert.ToUInt32("FFFFFFFF", 16) >> 24).ToString("X8"));
System.Diagnostics.Debug.WriteLine((Convert.ToUInt32("FFFFFFFF", 16) >> 32).ToString("X8"));

System.Diagnostics.Debug.WriteLine((Convert.ToUInt32("FF", 16) >> 8).ToString("X"));
System.Diagnostics.Debug.WriteLine((Convert.ToUInt32("FFFF", 16) >> 16).ToString("X"));
System.Diagnostics.Debug.WriteLine((Convert.ToUInt32("FFFFFF", 16) >> 24).ToString("X"));
System.Diagnostics.Debug.WriteLine((Convert.ToUInt32("FFFFFFFF", 16) >> 32).ToString("X"));

生产

00FFFFFF
0000FFFF
000000FF
FFFFFFFF

0
0
0
FFFFFFFF

谁能解释一下为什么会这样?

这是一个预期的记录行为 - 当计数为 32 移位时(int/uint)实际上是 0 位移位,因为只考虑了 5 个较低的位(32 & 0x1f是 0):

Bitwise and shift operators (C# reference): Shift count of the shift operators

If the type of x is int or uint, the shift count is defined by the low-order five bits of the right-hand operand. That is, the shift count is computed from count & 0x1F (or count & 0b_1_1111).


根据评论,您的实际问题似乎是“为什么 C# 设计者决定以这种方式定义它,而不是其他或更好的方式,但坚持类似于 C/C++ 的未定义行为”,这确实是意见基于(除非存在一些保存特定讨论和决定的官方设计文档):

虽然 UB 可能允许对生成的代码进行一些额外的优化或简化编译器,但它也会导致代码在与不同的编译器一起使用时可能会完全改变其行为。一般来说,您可能会发现 C# 和 .Net 更喜欢万无一失的正确性,而不是潜在的性能提升。 C/C++ 另一方面,更多地依赖于对语言边界有深入理解的开发人员来生成在所有编译器上运行相同的代码。

至于为什么选择特定行为 - 使用哪个特定选择来定义行为几乎无关紧要,因为不同的编译器/处理器对任何特定的未定义行为有不同的首选结果。

额外的考虑是易于记录——比如“如果第 16 位为 0 移位超过 31(对于有符号)和 32(无符号)产生 01 重复 16 次,否则对于有符号和减一无符号为零,除非计数大于 42,然后..."