VB6 IP4 - Calculate Net Mask (Long) from Number of Bits
Given input of 0 to 32, representing the number of one-bits in an IP4 network mask (corresponding to a CIDR block size as in /19), what's
- An elegant way开发者_开发问答 to turn that into a four-byte long net mask
- A fast way way to turn that into a four-byte long net mask
Prototype:
Function NetMaskFromBitCount(BitCount As Long) As Long
'Logic here '
End Function
Notice this is complicated by the fact that VB6 doesn't do unsigned, so regular math tricks often don't work. If (Number And &H80000000)
is nonzero, then Number \ 2
will NOT be the same as a SHR operation.
I've come up with a few ways, but I don't think they're elegant, and they're probably not that fast.
One idea I had is to strategically use the CopyMemory API, which is VERY fast. I've solved some signed/unsigned Long problems in the past by just blatting the Long into a Byte(0 To 3) and working with each portion as needed.
Since I'm also working with the inet_ntoa() and inet_addr() Windows API functions and they return the IP serial number in reverse byte order, a solution that returns the bytes in reverse order is great (I already have a function to flip the byte order if needed, but avoiding it would be nice, too).
Examples:
Input = 2
Output = -1073741824 (&HC0000000)
Alternate Output = 12 (&HC0, reverse byte order)
Input = 19
Output = -8192 (&HFFFFE000)
Alternate Output = 14745599 (&H00E0FFFF, reverse byte order)
Working solutions are good, but ELEGANT or FAST is what I'm looking for.
Function NetMaskFromBitCount(ByVal lBitCount As Long) As Long
If lBitCount > 0 Then
NetMaskFromBitCount = -1 * 2 ^ (32 - lBitCount)
End If
End Function
Had to make this param ByVal
!
And the test goes here:
Debug.Assert NetMaskFromBitCount(19) = &HFFFFE000
Debug.Assert NetMaskFromBitCount(2) = &HC0000000
Debug.Assert NetMaskFromBitCount(32) = &HFFFFFFFF
Debug.Assert NetMaskFromBitCount(0) = 0
You only have 32 possible inputs, so my guess is the fastest solution will be a lookup table referencing all 32 outputs from an array. It won't win points for elegance. Warning: air code
Function DoIt(ByVal Input As Long) As Long
Static lArray() As Long
Static bInitialised As Boolean
If Not bInitialised Then
ReDim Preserve lArray(0 To 31)
lArray(0) = 0
lArray(1) = &H80000000
lArray(2) = &HC0000000
' etc... '
bInitialised = True
End If
DoIt = lArray(Input) ' for bonus marks raises an error on illegal input '
End Function
If you want something more general, VBSpeed has a long-standing open competition for fast VB6 left-shifts.
- Here's the current winner
ShiftLeft04
which uses some horrendous, sorry I mean brilliant, tricks to get inline assembler in VB6. You'll laugh, you'll cry, you'll scream in terror... - The current runner-up ShiftLeft06 is about 200 lines of all-native VB6. Takes 1.3 times longer, but still quick.
I don't have VB6, but here is how I would do it in .Net
Const allBroadcast As Integer = Integer.MaxValue ' = 2,147,483,647
Dim mask As Integer
'three examples
mask = allBroadcast << (32 - 24) '/24
mask = allBroadcast << (32 - 16) '/16
mask = allBroadcast << (32 - 8) '/8
精彩评论