位移极限?

问题描述

我正在尝试根据CIDR表示法创建一个子网掩码。 /8表示8个前导位为1。我通过左移来实现此目的(我在这里使用32位)(uint)(0xffffffff << (32-8))

代码工作正常,直到我得到一个/0掩码,并生成代码(uint)(0xffffffff << 32)

现在向左移动(uint)(0xffffffff << 31)可以按预期10000000.00000000.00000000.00000000进行操作。

但是向左移动(uint)(0xffffffff << 32)会得到11111111.11111111.11111111.11111111。而预期结果将是00000000.00000000.00000000.00000000

解决这个问题的最简单方法是什么?使用if语句处理/0并将其全部设置为0?

解决方法

我会说正确的算法应该是这样的:

0xffffffff & (uint)((((ulong)0x1 << mask) - 1) << (32-mask))

mask是/

后的数字

我在这里用c#实现了它(因为您没有指定语言),并且似乎可以正常工作:https://dotnetfiddle.net/j1IfZP

,

来自documentation

左移操作将舍弃结果类型范围之外的高阶位,并将低阶空位位置设置为零

这意味着对于32位类型的左移,仅采用移位计数的低5位。由于32 = 0b10_0000,它需要6位存储,并且在屏蔽掉低5位之后,它将变为零。因此0xffffffff << 32等同于0xffffffff << 0

要解决这个问题,您要么需要提高精度

return (uint)(((1UL << mask) - 1) << (32 - mask))

或在换档前检查换档计数

return mask == 0 ? 0xFFFFFFFFU : 0xFFFFFFFFU << (32 - mask);

后者在32位平台上更好