What's the memory layout of bit field struct in little-endian and big-endian platform?

A

aling

Given the bit field struct:

int main()
{
union
{
struct
{
unsigned short s1 : 4;
unsigned short s2 : 3;
unsigned short s3 : 2;
} x;
char c;
} v;
v.c = 0x7A; // 0111 1010 b
printf( "%X", v.x.s3 );
}

What's the memory layout of bit field struct v after set v.c=0x7A in
little-endian platform and big-endian platform?
 
M

mlimber

aling said:
Given the bit field struct:

int main()
{
union
{
struct
{
unsigned short s1 : 4;
unsigned short s2 : 3;
unsigned short s3 : 2;
} x;
char c;
} v;
v.c = 0x7A; // 0111 1010 b
printf( "%X", v.x.s3 );
}

What's the memory layout of bit field struct v after set v.c=0x7A in
little-endian platform and big-endian platform?

It is unspecified and implementation-dependent. You should avoid
bitfields in C++ because:

1. They are non-portable, as you seem to have learned the hard way.
C++ARM says that the layout of bit-fields "is highly implementation
dependent, and it is wise not to make any assumptions about it unless
absolutely necessary." On a previous project, we used bit-fields for
mapping the contents of hardware registers, but when we eventually
ported the project to another platform with the other endianness, we
had to manually reverse the order of our many bit-fields. If I had time
and was still working on that project, I might try to use template
metaprogramming (a la Boost and Modern C++ Design) to engineer a more
portable solution akin to the Boost Parameter library
(http://boost.org/libs/parameter/doc/html/index.html). (N.B., I haven't
looked to see if anything like that already exists, and you might want
to. Compare this article discussing bitstreams in C++
http://www.cuj.com/documents/s=9897/cuj0510bishop/0510bishop.html .)

2. Some programmers mistakenly see bit-fields as a good form of space
or speed optimization. Consult C++ARM section 9.6 and C++PL section
C.8.1 for reasons why these forms of premature optimization often have
the opposite effect. In certain scenarios, bandwidth bottlenecks
*might* be eased by bit-packing. Just remember not to prematurely
optimize (http://www.gotw.ca/publications/mill09.htm). :)

Cheers! --M
 
P

Pete Becker

aling said:
What's the memory layout of bit field struct v after set v.c=0x7A in
little-endian platform and big-endian platform?

The C and C++ languages both say that after you've assigned to one
member of a union you can't read from other members. The behavior of
your code is undefined.

The other issue is that the layout of bitfields is
implementation-defined. Read your compiler's documentation to see what
they do.
 
P

Pete Becker

mlimber said:
It is unspecified and implementation-dependent. You should avoid
bitfields in C++ because:

You should use bitfields when they are appropriate.
1. They are non-portable,

Yes, that is correct. When you need 'em you need 'em. Non-portable is
often far more useful than strictly conforming code that doesn't
actually work with some compilers.
as you seem to have learned the hard way.

Well, more important is the misuse of the union.
C++ARM says that the layout of bit-fields "is highly implementation
dependent, and it is wise not to make any assumptions about it unless
absolutely necessary." On a previous project, we used bit-fields for
mapping the contents of hardware registers, but when we eventually
ported the project to another platform with the other endianness, we
had to manually reverse the order of our many bit-fields. If I had time
and was still working on that project, I might try to use template
metaprogramming (a la Boost and Modern C++ Design) to engineer a more
portable solution akin to the Boost Parameter library
(http://boost.org/libs/parameter/doc/html/index.html). (N.B., I haven't
looked to see if anything like that already exists, and you might want
to. Compare this article discussing bitstreams in C++
http://www.cuj.com/documents/s=9897/cuj0510bishop/0510bishop.html .)

It's much simpler to just rewrite the code that needs to be changed.
It's not that big. Portability is about being able to move across
platforms easily, and that means isolating platform-dependent code so
that it's easily identified and easily modified. Of course, that's
Old-Fashioned Design (TM), and I'm sure you can have much more fun, and
spend far more time, writing meta-programmed monstrosities that do part
of the job. Personally, I prefer productivity to cleverness.
 
M

mlimber

Pete said:
mlimber wrote: [snip]
C++ARM says that the layout of bit-fields "is highly implementation
dependent, and it is wise not to make any assumptions about it unless
absolutely necessary." On a previous project, we used bit-fields for
mapping the contents of hardware registers, but when we eventually
ported the project to another platform with the other endianness, we
had to manually reverse the order of our many bit-fields. If I had time
and was still working on that project, I might try to use template
metaprogramming (a la Boost and Modern C++ Design) to engineer a more
portable solution akin to the Boost Parameter library
(http://boost.org/libs/parameter/doc/html/index.html). (N.B., I haven't
looked to see if anything like that already exists, and you might want
to. Compare this article discussing bitstreams in C++
http://www.cuj.com/documents/s=9897/cuj0510bishop/0510bishop.html .)

It's much simpler to just rewrite the code that needs to be changed.
It's not that big. Portability is about being able to move across
platforms easily, and that means isolating platform-dependent code so
that it's easily identified and easily modified.

Ease of rewriting is application-specific, methinks. If there are a
multiplicity of bit-field structures and several varying compiler
implementations that they need to work with, things can get ugly for
several reasons. Rewriting will probably entail a lot of error-prone
cut-and-pasting, and it should be noted that it's difficult to write
test code for such things because that test code would also vary
between platforms. So, I would argue that it could be a big deal after
all, especially for mission-critical type work.
Of course, that's
Old-Fashioned Design (TM), and I'm sure you can have much more fun, and
spend far more time, writing meta-programmed monstrosities that do part
of the job. Personally, I prefer productivity to cleverness.

Well, I should first probably confess that I have used bit-fields
myself since working on the aforementioned project, but I did so mainly
because I lacked a better facility and didn't have time to metaprogram
one. I wish I had such a library, though, because it would allow me to
drop bit-fields altogether and have a portable (in the sense that it
compiles and works without modification) with a wide variety of
platforms and compilers. If such a library existed, many embedded
programmers would be saved a lot of dull, error-prone porting work.

Cheers! --M
 
G

Greg

aling said:
Given the bit field struct:

int main()
{
union
{
struct
{
unsigned short s1 : 4;
unsigned short s2 : 3;
unsigned short s3 : 2;
} x;
char c;
} v;
v.c = 0x7A; // 0111 1010 b
printf( "%X", v.x.s3 );
}

What's the memory layout of bit field struct v after set v.c=0x7A in
little-endian platform and big-endian platform?

Being implementation-dependent, the layout of the bitfield does not
conform to any one standard. In fact, a bitfield may be laid out the
same way on both big-endian and little-endian machines. Metrowerks
CodeWarrior, for example, has a #pragma reverse_bitfields that does
exactly that. (you may wonder who needs such a pragma - this pragma was
added so that Microsoft could compile Macintosh Office with
CodeWarrior).

Greg
 
P

Pete Becker

mlimber said:
Ease of rewriting is application-specific, methinks.
Obviously.

If there are a
multiplicity of bit-field structures and several varying compiler
implementations that they need to work with, things can get ugly for
several reasons. Rewriting will probably entail a lot of error-prone
cut-and-pasting,

Properly designed macros are usually a better solution than cut-and-paste.
and it should be noted that it's difficult to write
test code for such things because that test code would also vary
between platforms. So, I would argue that it could be a big deal after
all, especially for mission-critical type work.

Yes, writing portable code isn't trivial. Neither is meta-programming.
Either way, though, you damned well better be able to test what you've
done. "It's too hard" doesn't cut it.
Well, I should first probably confess that I have used bit-fields
myself since working on the aforementioned project, but I did so mainly
because I lacked a better facility and didn't have time to metaprogram
one.

You've just agreed with what I said. To put it more strongly: bitfields
work just fine for what they are designed to do. Which is probably why
there is no "better facility" through metaprogramming.
I wish I had such a library, though, because it would allow me to
drop bit-fields altogether and have a portable (in the sense that it
compiles and works without modification) with a wide variety of
platforms and compilers. If such a library existed, many embedded
programmers would be saved a lot of dull, error-prone porting work.

Well, maybe a small amount of moderately dull porting work. It's no more
error prone than relying on a library that attempts to detect the
essential criteria for laying out bit fields that are inherently
non-portable. And, of course, the way to make sure that porting the
bitfield code isn't error-prone is to write test cases, and use them.
 
M

mlimber

Pete said:
Properly designed macros are usually a better solution than cut-and-paste.

But then we're not talking about rewriting any more. Or, rather, we're
talking about rewriting the macros, and there's not so great a
difference in porting a preprocessor library and a metaprogrammed one.
Yes, writing portable code isn't trivial. Neither is meta-programming.
Either way, though, you damned well better be able to test what you've
done. "It's too hard" doesn't cut it.
Agreed.


You've just agreed with what I said. To put it more strongly: bitfields
work just fine for what they are designed to do. Which is probably why
there is no "better facility" through metaprogramming.

Perhaps, but the fact that this same question gets posted repeatedly on
this newsgroup may indicate a yearning of some kind. :) (See also the
similar-but-different article in CUJ that I cited in my first post.)
Well, maybe a small amount of moderately dull porting work. It's no more
error prone than relying on a library that attempts to detect the
essential criteria for laying out bit fields that are inherently
non-portable. And, of course, the way to make sure that porting the
bitfield code isn't error-prone is to write test cases, and use them.

The metaprogrammed solution that I am thinking of would manually
assemble the "bit-field" inside a standard integral type with explicit
bit-twiddling operations and would thus avoid implementation
dependencies for bit-fields. There is no way to detect, say, endinaness
at compile-time, but a few simple tests run in a library configuration
should easily be able to determine the right compiler/processor
configuration (and that's true of a macro library or a metaprogrammed
one). The library should, of course, supply a thorough set of tests for
itself that can be run on each platform.

Cheers! --M
 
P

Pete Becker

mlimber said:
But then we're not talking about rewriting any more. Or, rather, we'r
talking about rewriting the macros, and there's not so great a
difference in porting a preprocessor library and a metaprogrammed one.

I look forward to seeing your design for a metaprogrammed library that
manages bitfields. Until then, I'll continue to use macros.
 

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

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top