Bitmask vs bitfields

A

Andrew Shepson

Hi,

This question seems to come up quite often, however I haven't managed
to find an answer relevant to my case.

I often use binary flags, and I have alaways used a "bitmask"
technique, that is using #defined or const int powers of two, and
using the following primitives :
/* declaration and initizalisation of flags */ int flags = 0;
/* setting flag */ flags |= FLAG_1;
/* resseting flag */ flags &= ~FLAG_2;
/* conditional setting or resetting */ if (condition) flags |= FLAG_3;
else flags &= ~FLAG_3;
/* testing flags */ if ((flags & FLAG_4) || !(flags & FLAG_5)) { ... }
/* copy of the flag set */ other_flags = flags;

These are the only operations I ever use, they are only internal
representations. When I store or load or exchange data, I use a human-
readable text format, which basically boils down to setting or testing
flags with the above primitives.

I recently came across the "bitfield" concept, so an alernate solution
would be:
/* declaration and initizalisation of flags */
struct {
unsigned flag1 : 1;
unsigned flag2 : 1;
unsigned flag3 : 1;
unsigned flag4 : 1;
unsigned flag5 : 1;
} flags;

/* setting flag */ flags.flag1 = 1;
/* resetting flag */ flags.flag2 = 0;
/* condition setting or resetting */ flags.flag3 = (condition);
/* testing flags */ if (flags.flag4 || !flags.flag5) { ... }
/* copy fo the flag set */ other_flags = flags;

My first question is, is the last line correct? structure assignment
is a new concept for me, and I'm not familiar with it.

Are these codes portable? I have read quite a lot of portability
warning when using bitfields, however considering the limited set of
operations I used (in particular, the internal representation of the
bitfield is never taken into accoutn), I can't see any problem in it.

Is there any efficiency difference between the two methods? Of course,
it depends on the platform and the compiler, but there might be a rule
of thumb. I have read that the bitfield is usually less efficient,
however I can't see while a compiler with optimization turned on would
produce a different code than with the bitmask method.

With my naive point of view, I can see a few advantages to the
bitfield method : I find the code much more readable (especially for
testing), there is no namespace problems, and I don't have to care
whether or not I'm using more bits than the machine word or not (I
already had to use 34 flags on a 32-bits platform with 32-bits int and
long, and it was quite painful) so in that sense it seems more
portable than the bitmask method.

Could you please help me choosing between the two methods?

Thanks in advance.
 
E

Eric Sosman

Hi,

This question seems to come up quite often, however I haven't managed
to find an answer relevant to my case.

I often use binary flags, and I have alaways used a "bitmask"
technique, that is using #defined or const int powers of two, and
using the following primitives :
/* declaration and initizalisation of flags */ int flags = 0;
/* setting flag */ flags |= FLAG_1;
/* resseting flag */ flags&= ~FLAG_2;
/* conditional setting or resetting */ if (condition) flags |= FLAG_3;
else flags&= ~FLAG_3;
/* testing flags */ if ((flags& FLAG_4) || !(flags& FLAG_5)) { ... }
/* copy of the flag set */ other_flags = flags;

These are the only operations I ever use, they are only internal
representations. When I store or load or exchange data, I use a human-
readable text format, which basically boils down to setting or testing
flags with the above primitives.

I recently came across the "bitfield" concept, so an alernate solution
would be:
/* declaration and initizalisation of flags */
struct {
unsigned flag1 : 1;
unsigned flag2 : 1;
unsigned flag3 : 1;
unsigned flag4 : 1;
unsigned flag5 : 1;
} flags;

/* setting flag */ flags.flag1 = 1;
/* resetting flag */ flags.flag2 = 0;
/* condition setting or resetting */ flags.flag3 = (condition);

Careful! If `condition' is 6, say, the original treats it as
true but the rewrite treats it as false. Also, if `condition' is
something like `0.33' or `strchr(blah, 'x')', you'll get strange
results or possibly even a compilation error. Unless you're sure
that `condition' is an integer with the value 0 or 1, try one of

- `flags.flag3 = !!condition;'

- `_Bool flag3 : 1;' in the struct (C99 only)
/* testing flags */ if (flags.flag4 || !flags.flag5) { ... }
/* copy fo the flag set */ other_flags = flags;

My first question is, is the last line correct? structure assignment
is a new concept for me, and I'm not familiar with it.

Yes, structs have values and can be assigned. All the named
elements of the receiving struct receive the same values as the
corresponding elements of the original; unnamed padding bytes and
padding bits receive arbitrary values.
Are these codes portable? I have read quite a lot of portability
warning when using bitfields, however considering the limited set of
operations I used (in particular, the internal representation of the
bitfield is never taken into accoutn), I can't see any problem in it.

Your use of them is portable. The things to watch out for are
reliance on the arrangement of elements within the struct (as with
all structs), whether a plain-int bit-field is signed or unsigned
(but you're specifying unsigned explicitly), and avoiding widths that
are wider than int (which your 1-bit-wide flags aren't).
Is there any efficiency difference between the two methods? Of course,
it depends on the platform and the compiler, but there might be a rule
of thumb. I have read that the bitfield is usually less efficient,
however I can't see while a compiler with optimization turned on would
produce a different code than with the bitmask method.

Mu.
With my naive point of view, I can see a few advantages to the
bitfield method : I find the code much more readable (especially for
testing), there is no namespace problems, and I don't have to care
whether or not I'm using more bits than the machine word or not (I
already had to use 34 flags on a 32-bits platform with 32-bits int and
long, and it was quite painful) so in that sense it seems more
portable than the bitmask method.

Could you please help me choosing between the two methods?

Use whichever you're comfortable with, whichever you feel makes
the code more readable.
 
A

Andrew Shepson

Eric said:
Use whichever you're comfortable with, whichever you feel makes
the code more readable.

Eric

Thanks

I don't care about fine differences, when speed is really an issue
portability is no longer a concern and I measure to get the optimal
code
for the concerned platform.

However I do care about large differences. For example something like
"generally bitfield are vastly less effeciently implemented than
bitmask
because so few people use them" would have been enough to make me
reconsider the use of bitfields. I'm glad this is not the case.

PS: Why do you use
so many spaces and such short
lines?
 
I

ImpalerCore

Hi,

This question seems to come up quite often, however I haven't managed
to find an answer relevant to my case.

I often use binary flags, and I have alaways used a "bitmask"
technique, that is using #defined or const int powers of two, and
using the following primitives :
/* declaration and initizalisation of flags */ int flags = 0;
/* setting flag */ flags |= FLAG_1;
/* resseting flag */ flags &= ~FLAG_2;
/* conditional setting or resetting */ if (condition) flags |= FLAG_3;
else flags &= ~FLAG_3;
/* testing flags */ if ((flags & FLAG_4) || !(flags & FLAG_5)) { ... }
/* copy of the flag set */ other_flags = flags;

These are the only operations I ever use, they are only internal
representations. When I store or load or exchange data, I use a human-
readable text format, which basically boils down to setting or testing
flags with the above primitives.

I recently came across the "bitfield" concept, so an alernate solution
would be:
/* declaration and initizalisation of flags */
struct {
    unsigned flag1 : 1;
    unsigned flag2 : 1;
    unsigned flag3 : 1;
    unsigned flag4 : 1;
    unsigned flag5 : 1;

} flags;

/* setting flag */ flags.flag1 = 1;
/* resetting flag */ flags.flag2 = 0;
/* condition setting or resetting */ flags.flag3 = (condition);
/* testing flags */ if (flags.flag4 || !flags.flag5) { ... }
/* copy fo the flag set */ other_flags = flags;

My first question is, is the last line correct? structure assignment
is a new concept for me, and I'm not familiar with it.

Are these codes portable? I have read quite a lot of portability
warning when using bitfields, however considering the limited set of
operations I used (in particular, the internal representation of the
bitfield is never taken into accoutn), I can't see any problem in it.

Is there any efficiency difference between the two methods? Of course,
it depends on the platform and the compiler, but there might be a rule
of thumb. I have read that the bitfield is usually less efficient,
however I can't see while a compiler with optimization turned on would
produce a different code than with the bitmask method.

With my naive point of view, I can see a few advantages to the
bitfield method : I find the code much more readable (especially for
testing), there is no namespace problems, and I don't have to care
whether or not I'm using more bits than the machine word or not (I
already had to use 34 flags on a 32-bits platform with 32-bits int and
long, and it was quite painful) so in that sense it seems more
portable than the bitmask method.

Could you please help me choosing between the two methods?

I tend to prefer bitmasks over bitfields myself, but if I'm working
with a library that already uses bitfields, I have no problem going
with the flow.

There are a couple of minor annoyances with using bitfields. The
first is that some compilers in the embedded domain don't support
bitfields spanning multiple bytes, so bit operations are the only
recourse to storing bit information in 16-bit or larger blocks. The
other annoyance is that printing a hexadecimal or binary
representation of the bitfield requires converting the structure to an
integer type, or making the bitfield a union with an integer type.

One thing that I don't like about using bitmasks is that the
readability is pretty low. While the concept may be simple, the
implementation is not easily readable. That's why I like to implement
bitmask operations using macros so that the concept masks the
intricate details of what is needed to accomplish the task.

\code snippet
/*!
* \brief Define the integer type used to create a bitmask of zeros
with
* the least-significant bit enabled.
*
* One of the basic constructs used in the \c bits macro library is to
* create a mask that is all zero except for a single bit at a given
* index. This is often implemented using the simple expression
* <tt>1 << index</tt>. This is used to isolate single bits to be set
* or cleared within an integer.
*
* There is a caveat to consider when using this expression. The
issue
* is that the value of \c 1 is evaluated to be of type integer. For
* environments where the integer type is 16-bit, this expression will
* fail when trying to set a bit with an index >= 16 in a 32-bit long
* integer. A similar problem arises for 32-bit environments when
* trying to use \c 1 to set a bit at index >= 32 in a 64-bit integer.
* If this is an issue, there will typically be a warning that says
* that the left shift count is larger than the width of the integer
* type. If this error is found, \c C_BITS_ONE will need to be
defined
* as a larger integer type.
*
* The method to increase the width used by the macro library is to
* specify the type explicitly. This can be specified using a
stdint.h
* constant like <tt>UINT64_C(1)</tt> to enable support for 64-bit
* integers. Keep in mind that increasing the width beyond the
default
* integer type for the processor may incur a performance penalty for
* all macros.
*
* Ideally this should be configured using Autoconf or a Makefile, but
* for now its location is here. The \c C_BITS_ONE define can be \c 1
* for \c int sized masks, <tt>UINT32_C(1)</tt> to enable 32-bit
support
* on 16-bit integer platforms, or <tt>UINT64_C(1)</tt> to enable 64-
bit
* support.
*/
#define C_BITS_ONE (UINT32_C(1))

/*!
* \brief Determine if the bit at \c INDEX is set in \c WORD.
* \param WORD The word.
* \param INDEX The bit index.
* \return A non-zero value if the bit at \c INDEX is set, \c 0 if
clear.
*
* The \c INDEX range is from [0,N-1] where N is the number of bits
* of the \c WORD integer type.
*/
#define C_IS_BIT_SET(WORD, INDEX) (WORD & (C_BITS_ONE << (INDEX)))

/*!
* \brief Determine if the bit at \c INDEX is not set in \c WORD.
* \param WORD The word.
* \param INDEX The bit index.
* \return A non-zero value if the bit at \c INDEX is clear, \c 0 if
set.
*
* The \c INDEX range is from [0,N-1] where N is the number of bits
* of the \c WORD integer type.
*/
#define C_IS_BIT_CLEAR(WORD, INDEX) ( !(WORD & (C_BITS_ONE <<
(INDEX))) )

/*!
* \brief Set a single bit at \c INDEX in \c WORD.
* \param WORD The word.
* \param INDEX The bit index.
*
* The \c INDEX range is from [0,N-1] where N is the number of bits
* of the \c WORD integer type.
*/
#define C_SET_BIT(WORD, INDEX) (WORD |= (C_BITS_ONE << (INDEX)))

/*!
* \brief Clear a single bit at \c INDEX in \c WORD.
* \param WORD The word.
* \param INDEX The bit index.
*
* The \c INDEX range is from [0,N-1] where N is the number of bits
* of the \c WORD integer type.
*/
#define C_CLEAR_BIT(WORD, INDEX) (WORD &= ~(C_BITS_ONE << (INDEX)))
\endcode

For example, while setting a bit in a word is conceptually simple,
seeing it in bit operations directly is kind of ugly (and I have worse
macros than this). If you do go the bitmask route, making a set of
macros to implement your bitmask primitives is imo a good idea.

Best regards,
John D.
 
J

James Harris

Hi,

This question seems to come up quite often, however I haven't managed
to find an answer relevant to my case.

I often use binary flags, and I have alaways used a "bitmask"
technique, that is using #defined or const int powers of two, and
using the following primitives :
/* declaration and initizalisation of flags */ int flags = 0;
/* setting flag */ flags |= FLAG_1;
/* resseting flag */ flags &= ~FLAG_2;
/* conditional setting or resetting */ if (condition) flags |= FLAG_3;
else flags &= ~FLAG_3;
/* testing flags */ if ((flags & FLAG_4) || !(flags & FLAG_5)) { ... }
/* copy of the flag set */ other_flags = flags;

FYI, some other ops

http://codewiki.wikispaces.com/bitfield_operations.c

and further operations can be made wrapped in the read and write
options.
These are the only operations I ever use, they are only internal
representations. When I store or load or exchange data, I use a human-
readable text format, which basically boils down to setting or testing
flags with the above primitives.

I recently came across the "bitfield" concept, so an alernate solution
would be:
/* declaration and initizalisation of flags */
struct {
    unsigned flag1 : 1;
    unsigned flag2 : 1;
    unsigned flag3 : 1;
    unsigned flag4 : 1;
    unsigned flag5 : 1;

} flags;

/* setting flag */ flags.flag1 = 1;
/* resetting flag */ flags.flag2 = 0;
/* condition setting or resetting */ flags.flag3 = (condition);
/* testing flags */ if (flags.flag4 || !flags.flag5) { ... }
/* copy fo the flag set */ other_flags = flags;

My first question is, is the last line correct? structure assignment
is a new concept for me, and I'm not familiar with it.

Are these codes portable? I have read quite a lot of portability
warning when using bitfields, however considering the limited set of
operations I used (in particular, the internal representation of the
bitfield is never taken into accoutn), I can't see any problem in it.

Is there any efficiency difference between the two methods? Of course,
it depends on the platform and the compiler, but there might be a rule
of thumb. I have read that the bitfield is usually less efficient,
however I can't see while a compiler with optimization turned on would
produce a different code than with the bitmask method.

With my naive point of view, I can see a few advantages to the
bitfield method : I find the code much more readable (especially for
testing), there is no namespace problems, and I don't have to care
whether or not I'm using more bits than the machine word or not (I
already had to use 34 flags on a 32-bits platform with 32-bits int and
long, and it was quite painful) so in that sense it seems more
portable than the bitmask method.

Could you please help me choosing between the two methods?

For how you are using the fields NOW it looks like both forms would be
portable. For the sake of possible future changes, performance
(probably), consistency and compatibility I'd suggest using your own
bitfield operations. They may be less readable but can always be
wrapped in macros or functions to make them more readable.

Better yet, wrap up ALL operations on fields of bits and add methods
to convert them to and from an external text representation (for when
you load or exchange data). Then

1. you have a library for handling bit fields which you can reuse, and
debug separately

2. you can change the implementation - such as to try to get better
performance on a new compiler - without affecting code which uses it

3. your function names, if well chosen, will aid readability.

James
 
I

ImpalerCore

[snip]
Could you please help me choosing between the two methods?

For how you are using the fields NOW it looks like both forms would be
portable. For the sake of possible future changes, performance
(probably), consistency and compatibility I'd suggest using your own
bitfield operations. They may be less readable but can always be
wrapped in macros or functions to make them more readable.

Better yet, wrap up ALL operations on fields of bits and add methods
to convert them to and from an external text representation (for when
you load or exchange data). Then

Andrew could try out my 'c_bit_vsnprintf' implementation for writing a
text string of bits. Searching for that term should bring up a
comp.lang.c post on Apr 1.

[snip]
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top