EmbeddedRelated.com
Forums

Reason behind MISRA rule 111

Started by vikasvds May 12, 2011
In message <932rp0F87rU1@mid.dfncis.de>, Hans-Bernhard Br&#4294967295;ker
<HBBroeker@t-online.de> writes
>On 12.05.2011 20:16, David Brown wrote: > >> Bitfields have their uses, but you definitely want to check your >> compiler > >Actually from the point of view of MISRA C you have that backwards. The >moment you use any information you needed to check your compiler manual >for, you've left common ground, and made your code unportable.
You are wrong -- \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \/\/\/\/\ Chris Hills Staffs England /\/\/\/\/ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
On 12/05/2011 21:46, Hans-Bernhard Br&#4294967295;ker wrote:
> On 12.05.2011 20:16, David Brown wrote: > >> That's not the whole story. When you pick a type for a bitfield, you >> give several things - one is the /maximum/ allowed bitlength (such as >> 32 bits in this case). >> >> Another is the alignment. > > No, it's not. Portable C code has _no_ control over alignment > whatsoever, particularly not regarding bitfields. >
You are correct - /portable/ C does not define alignment for bitfields. But /practical/ C does - different compilers use different methods, and it can make a difference to the layout, alignment and padding of the fields. It may also affect the instructions used and the width of the accesses. As you say, /portable/ C has no control over alignment of bitfields - the C standards don't give any guidelines. It is up to the compiler, along with the standard ABI for the target, to determine the implementation. And for some implementations, the choice of the underlying type of the bitfield will influence the layout.
>> For example, if you write "struct { uint8_t a : 2; uint32_t b : 4; } >> bits" then bits.a will be at the start of the structure, followed by >> padding to allow b to fit within the next 32-bit alignment block. > > No. Nothing in the language definition requires any padding in this > case. That struct can perfectly legally fit into a single byte. >
Correct - and yet some /implementations/ will pad it into two bytes, or even more. A compiler could justify using 8 bytes for this struct (though the ones I tested with used 1 or 2 bytes).
>> You also affect the type of the extracted field - with the above >> structure on a 16-bit machine, "a" will be promoted to 16-bit int if >> you use it in arithmetic, while "b" will be promoted to 32-bit uint >> after extraction. > > Not necessarily, given that any compiler, including the one for that > unspecifited "16-bit machine" may not even allow you to _compile_ that > code, much less do what you think it should with it. >
Here, I think, you are wrong. The C standards only allow int, signed int and unsigned int as bitfield types - C99 also allows _Bool. In each case, the extracted field is given the type used in the bitfield declaration. C++ allows any integral type, including enumerations, as bitfield types - and again, on extraction the data takes on this type. Many C compilers allow other integral types in bitfields, and they follow the same rules as with C++. Again, this is not something in the C standards - it is something from practical reality. /If/ a compiler supports more general bitfield types, /then/ it will treat them as that type when the bitfield is extracted.
>> Bitfields have their uses, but you definitely want to check your >> compiler > > Actually from the point of view of MISRA C you have that backwards. The > moment you use any information you needed to check your compiler manual > for, you've left common ground, and made your code unportable. >
Bitfields are /always/ unportable. If nothing else, there is no standard defining the ordering of bitfields. Some compilers order them from the LSB, others from the MSB. MS Visual C++ actually changed this order between two versions of the compiler! So if you are writing portable code, you can't rely on bitfield details. It's fine if all you want to do is pack some data into a smaller space, for use entirely within a program. It is also okay to use them for inherently unportable code, such as for hardware registers - but you must check that your bitfield structure actually matches the hardware. Given these limitations, I'm actually surprised MISRA allows them at all.
>-----< David Brown > > Given these limitations, I'm actually surprised MISRA allows them at > all.
The idea with the MISRA rules and recommendations is, that when years later the stupidest schmuck in the world maintains your code, the probability that he misunderstands it and causes a bug shall be as low as possible. -- Fredrik &Ouml;stman
In message <mfGdnfBeVZcTa1HQnZ2dnUVZ8rOdnZ2d@lyse.net>, David Brown
<david@westcontrol.removethisbit.com> writes
>So if you are writing portable code, you can't rely on bitfield >details. It's fine if all you want to do is pack some data into a >smaller space, for use entirely within a program. It is also okay to >use them for inherently unportable code, such as for hardware registers >- but you must check that your bitfield structure actually matches the >hardware. > >Given these limitations, I'm actually surprised MISRA allows them at all.
MISRA has no view on portability as such. -- \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \/\/\/\/\ Chris Hills Staffs England /\/\/\/\/ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
On 13.05.2011 11:15, David Brown wrote:
> On 12/05/2011 21:46, Hans-Bernhard Br&#4294967295;ker wrote: >> On 12.05.2011 20:16, David Brown wrote:
>>> That's not the whole story. When you pick a type for a bitfield, you >>> give several things - one is the /maximum/ allowed bitlength (such as >>> 32 bits in this case).
>>> Another is the alignment.
>> No, it's not. Portable C code has _no_ control over alignment >> whatsoever, particularly not regarding bitfields.
> You are correct - /portable/ C does not define alignment for bitfields. > > But /practical/ C does - different compilers use different methods,
Indeed. And that's why every statement such as yours above claiming bitfields behave in any particular way is wrong by default. At the very minimum such a statement would have to be qualified by the exact version of a particular compiler it's supposed to be applicable for. Often the exact flags have to be specified, too.
> it can make a difference to the layout,
But you didn't say it "can". You say it _does_, without any restriction. That's where your claim became incorrect by insufficiently justified generalization.
> Correct - and yet some /implementations/ will pad it into two bytes, or > even more.
Yet you effectively claimed that they _all_ did so. And that again is an unjustified generalization.
> Here, I think, you are wrong. The C standards only allow int, signed int > and unsigned int as bitfield types - C99 also allows _Bool. In each > case, the extracted field is given the type used in the bitfield > declaration.
Relying on the behaviour of such non-standard bitfield types on usage is every bit as unportable as their very existence. Extensions to the language can behave whichever way they want. Yes, they'll usually behave sanely, following the guidance set forth by standard elements of the language. But there's no guarantee either way.
> Many C compilers allow other integral types in bitfields, and they > follow the same rules as with C++.
"Many" is an unreliable subset.
> Again, this is not something in the C standards - it is something from > practical reality. /If/ a compiler supports more general bitfield types, > /then/ it will treat them as that type when the bitfield is extracted.
And what evidence other than "I have never seen otherwise" do you have for that claim?
>> Actually from the point of view of MISRA C you have that backwards. The >> moment you use any information you needed to check your compiler manual >> for, you've left common ground, and made your code unportable.
> Bitfields are /always/ unportable.
No. Only relying on implementation-specific information about them makes them so. That's why I advised against even looking at that information. You can't abuse information you don't have.
On 13/05/2011 13:36, Hans-Bernhard Br&#4294967295;ker wrote:
> On 13.05.2011 11:15, David Brown wrote: >> On 12/05/2011 21:46, Hans-Bernhard Br&#4294967295;ker wrote: >>> On 12.05.2011 20:16, David Brown wrote: > >>>> That's not the whole story. When you pick a type for a bitfield, you >>>> give several things - one is the /maximum/ allowed bitlength (such as >>>> 32 bits in this case). > >>>> Another is the alignment. > >>> No, it's not. Portable C code has _no_ control over alignment >>> whatsoever, particularly not regarding bitfields. > >> You are correct - /portable/ C does not define alignment for bitfields. >> >> But /practical/ C does - different compilers use different methods, > > Indeed. And that's why every statement such as yours above claiming > bitfields behave in any particular way is wrong by default. At the very > minimum such a statement would have to be qualified by the exact version > of a particular compiler it's supposed to be applicable for. Often the > exact flags have to be specified, too. >
Point taken. What I really meant was that it these are factors that /could/ be affected by the choice of underlying type - as we know, there are no guarantees here.
>> it can make a difference to the layout, > > But you didn't say it "can". You say it _does_, without any restriction. > That's where your claim became incorrect by insufficiently justified > generalization. > >> Correct - and yet some /implementations/ will pad it into two bytes, or >> even more. > > Yet you effectively claimed that they _all_ did so. And that again is an > unjustified generalization. > >> Here, I think, you are wrong. The C standards only allow int, signed int >> and unsigned int as bitfield types - C99 also allows _Bool. In each >> case, the extracted field is given the type used in the bitfield >> declaration. > > Relying on the behaviour of such non-standard bitfield types on usage is > every bit as unportable as their very existence. > > Extensions to the language can behave whichever way they want. Yes, > they'll usually behave sanely, following the guidance set forth by > standard elements of the language. But there's no guarantee either way. >
Agreed.
>> Many C compilers allow other integral types in bitfields, and they >> follow the same rules as with C++. > > "Many" is an unreliable subset. >
True. There are a number of features in C that are implementation dependent, rather than being fixed by the standards. If your code relies on any of these features, you have to check how it works on the particular target and compiler combination you are using. Bitfields are just an area in which there are particularly many implementation-dependent issues. And of course just because the standards happen to be clear on a particular point, does not mean that any given compiler will actually follow them!
>> Again, this is not something in the C standards - it is something from >> practical reality. /If/ a compiler supports more general bitfield types, >> /then/ it will treat them as that type when the bitfield is extracted. > > And what evidence other than "I have never seen otherwise" do you have > for that claim? >
I haven't much more evidence, I admit - other than to claim that compiler writers who implement such extensions would normally do so in the clearest and most sensible way. If you know of counter examples, I'll be happy to accept them. And I will try to be more careful to qualify my points in this thread - though I think it is fairly clear that the lack of standards and consistency around bitfields makes /all/ points somewhat vague.
>>> Actually from the point of view of MISRA C you have that backwards. The >>> moment you use any information you needed to check your compiler manual >>> for, you've left common ground, and made your code unportable. > >> Bitfields are /always/ unportable. > > No. Only relying on implementation-specific information about them makes > them so. That's why I advised against even looking at that information. > You can't abuse information you don't have.
David Brown wrote:
> On 12/05/2011 21:46, Hans-Bernhard Br&#4294967295;ker wrote: >> Actually from the point of view of MISRA C you have that backwards. The >> moment you use any information you needed to check your compiler manual >> for, you've left common ground, and made your code unportable. > > Bitfields are /always/ unportable. If nothing else, there is no > standard defining the ordering of bitfields.
By the same argument, 'int' and 'double' would be unportable as well. But they have very well-defined properties you can use. And as long as you use only those properties, your code is portable. For example, a 'unsigned int foo : 1;' gives a neat place to store a bit. 100% portable. I use that all the time. It gets unportable when you 'memcpy' or 'fwrite' the structure containing it around, and make assumptions about the result. But that's no different for 'int' and 'double'. Stefan
On 13/05/11 18:21, Stefan Reuther wrote:
> David Brown wrote: >> On 12/05/2011 21:46, Hans-Bernhard Br&#4294967295;ker wrote: >>> Actually from the point of view of MISRA C you have that backwards. The >>> moment you use any information you needed to check your compiler manual >>> for, you've left common ground, and made your code unportable. >> >> Bitfields are /always/ unportable. If nothing else, there is no >> standard defining the ordering of bitfields. > > By the same argument, 'int' and 'double' would be unportable as well. > But they have very well-defined properties you can use. And as long as > you use only those properties, your code is portable. > > For example, a 'unsigned int foo : 1;' gives a neat place to store a > bit. 100% portable. I use that all the time. It gets unportable when you > 'memcpy' or 'fwrite' the structure containing it around, and make > assumptions about the result. But that's no different for 'int' and > 'double'. >
There is lots in C that is "implementation defined". Some aspects of "int" and "double" fall into this, such as their bit width. If you are writing portable code, you /do/ often avoid using "int" if the bit width is important. Instead, you use "int16_t", "uint32_t", or whatever you actually mean. Bitfields have lots of implementation-defined behaviour, and are therefore often non-portable. But as you say, they have certain well-defined aspects - if you only need to rely on those aspects, then your code is portable.
Arlet Ottens wrote:

> On 05/13/2011 12:10 AM, Vinzent Hoefler wrote: >> Hans-Bernhard Br=C3=B6ker wrote: >> >>> On 12.05.2011 20:16, David Brown wrote: >>> >>>> Bitfields have their uses, but you definitely want to check your >>>> compiler >>> >>> Actually from the point of view of MISRA C you have that backwards. =
The
>>> moment you use any information you needed to check your compiler man=
ual
>>> for, you've left common ground, and made your code unportable. >> >> Using bitfields and expecting a certain representation is unportable >> anyway, as the Endianess of bit-fields is implementation-defined. > > A lot of stuff is implementation defined, such as representation of > integers and floats. It doesn't have to be a problem, unless you move > the binary representation from one implementation to another.
It is a problem, if you rely on a certain representation, "(unsigned) in= t" or not. So I don't think, this particular MISRA rule had close-to-100% portability in mind.
> If you use the bitfields only internally, there are no portability > concerns.
LOL. It would be nice to use bitfields to define device register and that simply ain't possible in a "portable" (e.g. compiler-independent) way, because the representation may change once a different compiler has been= chosen by the customer. BTSTFU. The only "portable" way to use bitfields at that time was to define a collection of flags which were situated at something the Z80 programmer knows as zero-page to cut down code size by a couple of bytes because then direct bit addressing was possible. If that's all that bitfields can deliver, they sure are close to useless, I'd say. Vinzent. -- = A C program is like a fast dance on a newly waxed dance floor by people = carrying razors. -- Waldi Ravens
On 05/13/2011 10:28 PM, Vinzent Hoefler wrote:

>> If you use the bitfields only internally, there are no portability >> concerns. > > LOL. > > It would be nice to use bitfields to define device register and that > simply ain't possible in a "portable" (e.g. compiler-independent) way, > because the representation may change once a different compiler has been > chosen by the customer. BTSTFU.
I meant internally, only as a method to cram more data in the same memory. Using bitfields in device interfaces, is no longer 'internal'. Still, you could define device registers using bitfields, if you include some #ifdef COMPILER_XYZ around it, followed by #else #error Please add register definitions for this compiler #endif Which exposes portability problems. Switching compilers mid-project is pretty rare anyway, and very few embedded projects are 100% portable between compilers. Try implementing a portable interrupt handler, for instance.