Any compiler that fails to recognize code that uses bit fields is not standard-compliant. What they probably mean is that the fields themselves may be packed unpredictably in location and order (allowed by the standard, previous ref.
This means that a struct with e.g. four bit fields of size 4, 12, 13 and 3 does not necessarily take up 32 bits, and they won't necessarily be placed within the struct in that order; the compiler can place them where it likes. This means that the struct cannot be treated as an actual component-wise representation of an underlying binary object.
In contrast, bit masks applied manually to integers exist exactly where you put them. Of an unsigned integer, the fields will actually apply to the bits, in order and in position (assuming you know the endangers, anyway).
As such it may be necessary to use a preprocessor directive to check for the endangers of the machine. The address operator (&) cannot be applied to bit -field members.
The data type of bit -field must be wide enough to contain the size of the field. A bit -field is used to club together many variables into one object, similar to a structure.
This allows for reduced memory usage and is especially useful in an embedded environment. If we declare these variables separately, then each has to be at least an 8- bit integer and the total space required will be 5 bytes.
Moreover, the variables will not use the entire range of an 8 bit unsigned integer (0-255). The programmer needs to take care that the variables are written in range.
You can argue that the bit field method is easier to write, but it also means more code to review. If the issue is that setting and clearing bits is error prone, then the right thing to do is to write functions or macros to make sure you do it right.
Which makes your code readable if you don't mind that val has to be a value except for BIT _IS_SET. Bit fields are great and easy to read, but unfortunately the C language does not specify the layout of bit fields in memory, which means they are essentially useless for dealing with packed data in on-disk formats or binary wire protocols.
However, the noob will likely need to overcome a large learning curve before they are able to maintain your code. You're almost certainly going to have bugs introduced by the noob as he/she all the tricks required to get this to work.
On the other hand, if you write to satisfy the second audience, the noobs will have an easier time maintaining the code. And the first audience will just get grumpy, but it's hard to imagine they wouldn't be able to grok and maintain the new syntax.
The union usage has undefined behavior according to the ANSI C standard, and thus, should not be used (or at least not be considered portable). ) The value of a structure or union object is never a trap representation, even though the value of a member of the structure or union object may be a trap representation.
So, if you want to keep the bit field integer correspondence, and to keep portability, I strongly suggest you to use the bit masking method, that contrary to the linked blog post, it is not poor practice. For simple “one-off” bit fiddling, I use the bitwise operators directly.
Bit fields also seamlessly handle structures bigger than a single int. With bitwise operators, typical (bad) practice is a slew of #defines for the bit masks.
The only caveat with bit fields is to make sure the compiler has really packed the object into the size you wanted. I can't remember if this is defined by the standard, so an assert(size of(instruct) == N) is a useful check.
The blog post you are referring to mentions raw union field as alternative access method for bit fields. The purposes blog post author used raw for are ok, however if you plan to use it for anything else (e.g. serialization of bit fields, setting/checking individual bits), disaster is just waiting for you around the corner.
The ordering of bits in memory is architecture dependent and memory padding rules vary from compiler to compiler (see Wikipedia), so exact position of each bit field may differ, in other words you never can be sure which bit of raw each bit field corresponds to. Well you can't go wrong with structure mapping since both fields are accessible they can be used interchangeably.
In some environments such as dealing with protocol options it can get quite old having to individually set options or use multiple parameters to ferry intermediate states to effect a final outcome. But sometimes setting flag. Blah and having the list popup in your IDE is great especially if your like me and can't remember the name of the flag you want to set without constantly referencing the list.
I personally will sometimes shy away from declaring boolean types because at some point I'll end up with the mistaken impression that the field I just toggled was not dependent (Think multi-thread concurrency) on the r/w status of other “seemingly” unrelated fields which happen to share the same 32- bit word. My vote is that it depends on the context of the situation and in some cases both approaches may work out great.
Either way, bit fields have been used in GNU software for decades, and it hasn't done them any harm. Everyone knows how to AND the values to set various options off and the compiler boils this down to very efficient bitwise operations on the CPU.
Providing you use the masks and tests in the correct way, the abstractions the compiler provide should make it robust, simple, readable and clean. I've seen lots of errors in this kind of code, mainly because some people feel that they should mess with it and the business logic in a totally disorganized way, creating maintenance nightmares.
Even better if there's some increment operator around, a couple of memcpy's, pointer casts and whatever obscure and error-prone syntax happens to come to their mind at that time. Of course there's no need to be consistent, and you can flip bits in two or three different ways, distributed randomly.
Programmers who can't handle fundamentals like “|&^~” are probably in the wrong line of work. I nearly always use the logical operations with a bit mask, either directly or as a macro.
Incidentally your union definition in the original question would not work on my processor/compiler combination. The int type is only 16 bits wide and the bit field definitions are 32.
To make it slightly more portable than you would have to define a new 32 bit type that you could then map to the required base type on each target architecture as part of the porting exercise. If you ever have to write MIRA -compliant code, the MIRA guidelines frown on bit fields, unions, and many, many other aspects of C, in order to avoid undefined or implementation-dependent behavior.
Bit fields are great, except that the bit manipulation operations are not atomic, and can thus lead to problems in multi-threaded application. But the ordinary code generated by a compiler will not try to make |= atomic.
The compiler is free to arrange bits within a bit field any way it wants. This is mean if you're trying to manipulate bits in a microcontroller register, or if you want to send the bits to another processor (or even the same processor with a different compiler), you MUST use bit masks.
On the other hand, if you're trying to create a compact representation of bits and small integers for use within a single processor, bit fields are easier to maintain and thus less error prone, and -- with most compilers -- are at least as efficient as manually masking and shifting.