Bit fields in VB.NET Structures

C

Charles Law

Sorry for asking this one again, but with the newsgroup now holding things
for an ever shorter time, I can't find my original question (and the
answers) from a few months ago.

I know that structures in VB.NET don't have bit fields, but I am looking for
a convenient way to reproduce the convenience afforded in C/C++.

If I have

typedef struct _MyStruct {
DWORD First
DWORD Second : 1
DWORD Third : 1
DWORD Fourth : 2
...
} MyStruct;

I would be forced to translate this into

Public Structure MyStruct
Dim First As Integer
Dim Flags As Integer
...
End Structure

and decode the values of Flags.

Does anyone have any suggestions for an elegant way to deal with this
scenario, ideally getting the benefit of intellisense, so that I can say

Flags = ValueOfThird

resulting in just bit 1 of the Flags element becoming set? Perhaps using an
enum with the FlagsAttribute?

Thanks.

Charles
 
L

Lloyd Sheen

Create properties First, Second, etc. In the get and put do whatever
processing has to be done to extract the bit and set / clear the bit.


Lloyd Sheen
 
J

Jay B. Harlow [MVP - Outlook]

Charles,
In addition to the other's comments. I have used the
System.Collections.Specialized.BitVector32 to represent the bit fields with
some success.

Here is something I wrote about it a few months ago:

When I implemented the DCB structure in VB.NET I defined Flags as a Private
BitVector32. Then used Property procedures that extracted the individual
values, using the methods of BitVector32.

Public enum RtsControl As Byte
Disable = 0
Enable = 1
Handshake = 2
Toggle = 3
End Enum

Public Structure DBC
...
Private Flags As BitVector32
...

Private Shared Readonly m_fBinary As Integer
Private Shared Readonly m_Parity As Integer
...
Private Shared Readonly m_fRtsControl As BitVector32.Section
...

Shared Sub New()
' create boolean masks
m_fBinary = BitVector32.CreateMask()
...
m_fParity = BitVector32.CreateMask(m_fBinary)
...
' create section masks
Dim previousSection As BitVector32.Section
previousSection = BitVector32.CreateSection(1)
...
m_fRtsControl = BitVector32.CreateSection(3,
previousSection)
...
End Sub

Public Property Binary As Boolean
Get
Return Flags.Item(m_fBinary)
End Get
Set(ByVal value As Boolean)
Flags.Item(m_fBinary) = value
End Set
End Property

...

Public Property RtsControl As RtsControl
Get
Return CType(Flags.Item(m_fRtsControl), RtsControl)
End Get
Set(ByVal value As RtsControl)
Flags.Item(m_fRtsControl) = value
End Set
End Property

...

End Structure

BitVector32 is marshaled as an Integer (DWORD) so you can use them
interchangeably.

I made Flags Private as its an implementation detail.

The property procedures expose the flags as the respective types, For
example RtsControl & DtrControl as enums with valid values, others as
Boolean. I had to change a couple names as there is a field & a flag
(ErrorChar).

For the BitVector32 masks I had to make two passes, once for the boolean
values, then a second one for the section (enum) values.

Using the BitVector32 class simplified my property procedures at the
"expense" of a little extra setup (the shared constructor).

I have not posted my class on got dot net yet, as I am still working on
making the WaitEvent async.

Hope this helps
Jay
 
T

Tom Shelton

Charles,
In addition to the other's comments. I have used the
System.Collections.Specialized.BitVector32 to represent the bit fields with
some success.

Jay,

That is pretty slick... I'm going to have to remember that one :)
 
C

Charles Law

Jay

That's exactly the kind of thing I was hoping for. Thanks. And thanks also
to Lloyd for a similar suggestion.

I think you alluded to this last time I asked the question, and it so
happens that it is the DCB I am doing this for.

I have now printed it out for reference.

Cheers

Charles
 
C

Charles Law

Jay

As I am implementing this along the lines you describe, a couple of
questions occur.

Why are the variables m_fBinary, etc. Shared, and why ReadOnly, as they are
read and written, and all instances of DCB will share the same values. For
example, if I read the DCB first and want to keep a copy so I can reset it
at the end, when I change the values of the current DCB it will change my
copy as well, won't it?

Where you have put ... in Sub New(), I am not sure what the missing bits
should be. Could you add a few extra lines to make it a bit clearer (to me)?

Thanks again.

Charles
 
O

Ot

I am old to programming in general and new to VB (just to give the context
of my remarks.)

It is my understanding that "Private Shared" would make variables that are
the same across all instantiations of the class. But note that this is a
structure, not a class. Structures, I have been told, are your unique data
types and are treated as such. I, too, am confused as to the meaning of
"Shared" in a structure.

Awaiting the answer with bated breath.
 
J

Jay B. Harlow [MVP - Outlook]

Charles,
Shared Readonly fields are effectively Constants, in that a single copy of
them exist and you cannot change them. The cool thing about them (over a
constant) is you can set them at run time!

Seeing as those fields are the indexes & masks into the BitVector itself,
only a single copy of them need to exist and once they are set (in the
shared constructor) they do not change for the life of the program, seeing
as I am using the Shared methods on BitVector to "calculate" them I cannot
use a regular constant field, as you cannot call methods on an object or
class at compile time.

Note the BitVector itself is the instance variable, so each instance of the
class or structure will have a copy of the BitVector, however you only need
a single copy of the indexes & masks into this BitVictor.
Where you have put ... in Sub New(), I am not sure what the missing bits
should be. Could you add a few extra lines to make it a bit clearer (to
me)?
They go in the Shared Sub New, you need a CreateMask call for each "bit" in
the BitVector, same with CreateMask.

Hope this helps
Jay
 
C

Charles Law

Jay

Reading about BitVector32, MSDN states

<quote>
A BitVector32 structure can be set up to contain either sections for small
integers or bit flags for Booleans, but not both.
</quote>

However, you example appears to show both. When I tried to implement it I
ran into problems with the mask and section variables:

Private Shared ReadOnly m_fBinary As Integer
Private Shared ReadOnly m_fParity As Integer
Private Shared ReadOnly m_fOutxCtsFlow As Integer
Private Shared ReadOnly m_fOutxDsrFlow As Integer
Private Shared ReadOnly m_fDtrControl As BitVector32.Section
....

m_fBinary = BitVector32.CreateMask()
m_fParity = BitVector32.CreateMask(m_fBinary)
m_fOutxCtsFlow = BitVector32.CreateMask(m_fParity)
m_fOutxDsrFlow = BitVector32.CreateMask(m_fOutxCtsFlow)
m_fDtrControl = BitVector32.CreateMask(m_fOutxDsrFlow)
m_fDsrSensitivity = BitVector32.CreateMask(m_fDtrControl)
....

where the last two lines cause a compile error.

I have done the following

Private Shared ReadOnly m_fBinary As BitVector32.Section
Private Shared ReadOnly m_fParity As BitVector32.Section
Private Shared ReadOnly m_fOutxCtsFlow As BitVector32.Section
Private Shared ReadOnly m_fOutxDsrFlow As BitVector32.Section
Private Shared ReadOnly m_fDtrControl As BitVector32.Section
....

m_fBinary = BitVector32.CreateSection(1)
m_fParity = BitVector32.CreateSection(1, m_fBinary)
m_fOutxCtsFlow = BitVector32.CreateSection(1, m_fParity)
m_fOutxDsrFlow = BitVector32.CreateSection(1, m_fOutxCtsFlow)
m_fDtrControl = BitVector32.CreateSection(3, m_fOutxDsrFlow)
m_fDsrSensitivity = BitVector32.CreateSection(1, m_fDtrControl)
....

I have not included any CreateMask statements. All seems to be working well.
Have I missed something?

Charles
 
J

Jay B. Harlow [MVP - Outlook]

Charles,
Doh! I did not read that section of MSDN. ;-)

You are correct my sample uses both and both work!

The one caveat that I know of with BitVector32 is that you cannot use the
"high" bit of the underlying Int32 (the 32nd bit, starting with bit 1).

CreateMask only works with Integers.
CreateSection only works with Sections.

I actually made two passes, one pass to calculate the "Masks" using dummy
variables for fDtrControl. Then a second pass to calculate the "Sections"
using dummy variables for fBinary, fParity...

You can use only CreateSection, however getting the Booleans in & out of the
BitVector was then "more work" then I wanted in my property procedures...

Hope this helps
Jay
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top