I'm trying to create a subnet mask from CIDR notation eq. /8
would mean that the 8 leading bits would be 1's. I'm achieving this by left shifting (I'm working with 32 bits here) (uint)(0xffffffff << (32-8))
.
The code works fine until I get a /0
mask which leads to the code (uint)(0xffffffff << 32)
Now left shifting (uint)(0xffffffff << 31)
works as intended 10000000.00000000.00000000.00000000
.
But left shifting (uint)(0xffffffff << 32)
gives 11111111.11111111.11111111.11111111
. While expected outcome would be 00000000.00000000.00000000.00000000
.
What's the simplest way around this? Handle /0
with a if-statement and just set all to 0?
From the documentation:
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
That means for shifting left on a 32-bit type, only the low 5 bits in the shift count is taken. Since 32 = 0b10_0000 which needs 6 bits to store and after masking out the low 5 bits it'll become zero. So 0xffffffff << 32
is equivalent to 0xffffffff << 0
To solve that you either need to shift in a higher precision
return (uint)(((1UL << mask) - 1) << (32 - mask))
or check the shift count before shifting
return mask == 0 ? 0xFFFFFFFFU : 0xFFFFFFFFU << (32 - mask);
The latter is better on 32-bit platforms