Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Accessing bit fields of a structure

Reply
Thread Tools

Accessing bit fields of a structure

 
 
lancer6238@yahoo.com
Guest
Posts: n/a
 
      06-15-2009
Hi,

I'm trying to write a structure to represent the header of a GRE
packet, then access each component in the header. However, I have
problems getting the right values for the bit fields.

Here's what I have:

struct grehdrv0
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int version:3;
unsigned int flags:5;
unsigned int recur:3;
unsigned int s:1;
unsigned int S:1;
unsigned int K:1;
unsigned int R:1;
unsigned int C:1;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int C:1;
unsigned int R:1;
unsigned int K:1;
unsigned int S:1;
unsigned int s:1;
unsigned int recur:3;
unsigned int flags:5;
unsigned int version:3;
#else
#error "Please fix <bits/endian.h>
u_int16_t protocol;
/* Optional fields */
}

I'm trying to access the bit fields using:

struct grehdrv0 *gre;
....
// gre now points to the gre header portion of the packet
printf("%d %d %d %d %d %d %d %d %x\n", gre->C, gre->R, gre->K, gre->S,
gre->s, gre->recur, gre->flags, gre->version, ntohs(gre->protocol));

The first 16 bits should be (in binary) 0011 0000 1000 0001. However,
I am unable to get the correct values for the first 16 bits of the
header (I got in decimal 1 0 0 0 0 1 6 0), but gre->protocol gives me
the correct value.

How do I access the bit fields?

Thank you.
 
Reply With Quote
 
 
 
 
Beej Jorgensen
Guest
Posts: n/a
 
      06-15-2009
http://www.velocityreviews.com/forums/(E-Mail Removed) <(E-Mail Removed)> wrote:
>I'm trying to write a structure to represent the header of a GRE
>packet, then access each component in the header. However, I have
>problems getting the right values for the bit fields.


It's so tempting to just overlay a bitfield struct right onto the packet
data, isn't it? It's perfect! I mean, what could possibly go wrong?

The problem is the compiler is free to take extreme liberties with
bitfields, so they're not guaranteed (or perhaps even likely) to be
packed in the way you hope.

C99 6.7.2.1p10:

# An implementation may allocate any addressable storage unit large
# enough to hold a bitfield. If enough space remains, a bit-field that
# immediately follows another bit-field in a structure shall be packed
# into adjacent bits of the same unit. If insufficient space remains,
# whether a bit-field that does not fit is put into the next unit or
# overlaps adjacent units is implementation-defined. The order of
# allocation of bit-fields within a unit (high-order to low-order or
# low-order to high-order) is implementation-defined. The alignment of
# the addressable storage unit is unspecified.

So all bets are off. It looks like you're accessing the bitfields
correctly when you print them, but the bitfields in the struct aren't
aligning properly with the raw packet data (because the compiler is
allowed to change their alignment, allocation order, etc.)

You're going to have to do it the old-fashioned way and manually check
which bits are set by peering into your char buffer that holds the
packet. Macros might make your life easier in this case.

-Beej

 
Reply With Quote
 
 
 
 
James Dow Allen
Guest
Posts: n/a
 
      06-15-2009
On Jun 15, 3:18 pm, "(E-Mail Removed)" <(E-Mail Removed)>
wrote:
> Hi,
> #if __BYTE_ORDER == __LITTLE_ENDIAN
> #elif __BYTE_ORDER == __BIG_ENDIAN


For your purpose there may be more than two types
of "Endianness". Three or four patterns *might* cover
all cases.

> unsigned int ... :3,5,3,1,1,1,1,1
>
> The first 16 bits should be (in binary) 0011 0000 1000 0001


Let's change the spacing in that binary number
and assign fields empirically.

00110 000 1 0 0 0 0 001.
[5]=6 [3]=0 [1]=1 [1]=0 [1]=0 [1]=0 [1]=0 [3]=1

> However, ... (I got in decimal 1 0 0 0 0 1 6 0),


I'm surprised you didn't experiment with more data values.
I had little trouble figuring out the straightforward
bit assignment, but with, e.g. a single 1-bit rippling
it would have become very obvious.

On Jun 15, 4:09*pm, Beej Jorgensen <(E-Mail Removed)> wrote:
>
> The problem is the compiler is free to take extreme liberties with
> bitfields, so they're not guaranteed (or perhaps even likely) to be
> packed in the way you hope.
>
> [Standard excerpt snipped]


Note that OP's example does *not* have fields spanning an 8-bit
boundary,
and is a nice multiple of 8 bits in length. The standard excerpt
quoted *might* even lead to a *proof* that at most 4 patterns are
possible, but I'll leave that to the C lawyers.

> So all bets are off....
> You're going to have to do it the old-fashioned way...


I'm certainly no C lawyer, but I'd bet 3 or 4 cases would
cover everything except, possibly, "hypothetical" compilers.
But, rather than coding a painful 'config', it would
be easiest to follow Beej's suggestion and avoid bitfields.

The reason I'm following up is that *I continue to believe*
that some "C lawyers" insist on coding for compilers that
are about as real as the Tooth Fairy. In a recent thread,
I changed code to allow for padding bits. Eventually,
the resident expert admitted machines with such padding
"might be purely hypothetical."

James Dow Allen
 
Reply With Quote
 
Boon
Guest
Posts: n/a
 
      06-15-2009
lancer wrote:

> I'm trying to write a structure to represent the header of a GRE
> packet, then access each component in the header. However, I have
> problems getting the right values for the bit fields.
>
> Here's what I have:
>
> struct grehdrv0
> {
> #if __BYTE_ORDER == __LITTLE_ENDIAN
> unsigned int version:3;
> unsigned int flags:5;
> unsigned int recur:3;
> unsigned int s:1;
> unsigned int S:1;
> unsigned int K:1;
> unsigned int R:1;
> unsigned int C:1;
> #elif __BYTE_ORDER == __BIG_ENDIAN
> unsigned int C:1;
> unsigned int R:1;
> unsigned int K:1;
> unsigned int S:1;
> unsigned int s:1;
> unsigned int recur:3;
> unsigned int flags:5;
> unsigned int version:3;
> #else
> #error "Please fix <bits/endian.h>
> u_int16_t protocol;
> /* Optional fields */
> }
>
> I'm trying to access the bit fields using:
>
> struct grehdrv0 *gre;
> ...
> // gre now points to the gre header portion of the packet
> printf("%d %d %d %d %d %d %d %d %x\n", gre->C, gre->R, gre->K, gre->S,
> gre->s, gre->recur, gre->flags, gre->version, ntohs(gre->protocol));
>
> The first 16 bits should be (in binary) 0011 0000 1000 0001. However,
> I am unable to get the correct values for the first 16 bits of the
> header (I got in decimal 1 0 0 0 0 1 6 0), but gre->protocol gives me
> the correct value.


1 0 0 0 0 1 6 0 <-> 10000001 00110000

What does your program print given

struct grehdrv0 foo;
struct grehdrv0 *gre = &foo;
uint8_t *p = (uint8_t *)gre;
p[0] = 0x47;
p[1] = ~0x47;

> How do I access the bit fields?


Do you need your code to be portable?

CHAR_BIT > 8 adds a layer of complexity.

Can you assume POSIX? (which mandates CHAR_BIT =

Regards.
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      06-15-2009
James Dow Allen wrote:
....
> The reason I'm following up is that *I continue to believe*
> that some "C lawyers" insist on coding for compilers that
> are about as real as the Tooth Fairy.


When I write C code, I write it for compilers which conform fully to the
C standard. I refuse to write C code which make assumptions about
matters that the C standard leaves unspecified unless they are instead
specified as part of the requirements for the program I'm writing. Some
of the assumptions I refuse to make might be violated only by compilers
no more real than the Tooth Fairy; but that doesn't mean I'm actually
coding for such compilers. I suspect that such assumptions are rarer
than you think they are; in many cases, compilers violating the
assumption are only as unreal as gcc 6.0.0 - i.e. they are compilers
that haven't been written yet, but might get written before the lifetime
of my code ends.

I just find it easier to follow a consistent rule, than to evaluate each
possible deviation from that rule for it's likelihood of causing problems.
 
Reply With Quote
 
Beej Jorgensen
Guest
Posts: n/a
 
      06-15-2009
James Dow Allen <(E-Mail Removed)> wrote:
>Note that OP's example does *not* have fields spanning an 8-bit
>boundary,


This is a keen observation that I missed; nevertheless, with the
possibility of padding insertion and bit reversal, it's still going to
be "interesting" to get the overlain struct to make sense in all cases.

>The standard excerpt quoted *might* even lead to a *proof* that at most
>4 patterns are possible, but I'll leave that to the C lawyers.


This would be an interesting thing to see. With the the amount of
padding between struct elements being variable, I would think it would
be difficult to code for.

>The reason I'm following up is that *I continue to believe* that some
>"C lawyers" insist on coding for compilers that are about as real as
>the Tooth Fairy.


Well, at least in this case, that wasn't my intent. I distinctly
remember trying to do exactly this thing years ago with packets,
structs, and bitfields, and having it fail.

And I don't have anything against non-portable code when you know what
you're getting into. (I've calculated the length of a function by
subtracting function pointers--and I'm not even going to apologize!) But
in this case, the struct layout in memory could change on the same
platform with the same compiler just by changing the optimization
flags... it seems like it's just asking for trouble--proper trouble--to
code around it.

-Beej

 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      06-15-2009
Beej Jorgensen <(E-Mail Removed)> writes:

> James Dow Allen <(E-Mail Removed)> wrote:
>>Note that OP's example does *not* have fields spanning an 8-bit
>>boundary,

>
> This is a keen observation that I missed; nevertheless, with the
> possibility of padding insertion and bit reversal, it's still going to
> be "interesting" to get the overlain struct to make sense in all
> cases.


Padding is not permitted, at least not "in general". Consecutive
fields must be packed into the same storage unit and the
implementation must document the order in which this happens. This is
why James' observation is a good one. If you are writing
non-portable code, you *can* rely on some properties of bit fields.

I agree that they are a potability nightmare, but that is not always
the issue.

>>The standard excerpt quoted *might* even lead to a *proof* that at most
>>4 patterns are possible, but I'll leave that to the C lawyers.

>
> This would be an interesting thing to see. With the the amount of
> padding between struct elements being variable, I would think it would
> be difficult to code for.


Padding of bit fields can only happen when the size is such that it
does not fit in the space remaining in the current "unit". The
implementation must also document what happens in this case and there
are only two possibilities.

<snip>
> And I don't have anything against non-portable code when you know what
> you're getting into. (I've calculated the length of a function by
> subtracting function pointers--and I'm not even going to apologize!) But
> in this case, the struct layout in memory could change on the same
> platform with the same compiler just by changing the optimization
> flags... it seems like it's just asking for trouble--proper trouble--to
> code around it.


Not likely. There would have to be some odd flag like
-use-optimal-9-bit-chars for this to occur and, if it does, the
implementation must document the new packing rules or it will not be
conforming.

Bit fields have huge problems, but they have fewer problems than they
are often portrayed as having!

--
Ben.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      06-15-2009
Beej Jorgensen <(E-Mail Removed)> writes:
[...]
> And I don't have anything against non-portable code when you know what
> you're getting into. (I've calculated the length of a function by
> subtracting function pointers--and I'm not even going to apologize!) But
> in this case, the struct layout in memory could change on the same
> platform with the same compiler just by changing the optimization
> flags... it seems like it's just asking for trouble--proper trouble--to
> code around it.


Varying struct layout depending on compiler flags is permitted (each
set of flags effectively specifies a distinct implementation as
far as the standard is concerned), but it could cause some serious
problems. For example, if a struct is declared in a header file,
then all translation units that include that header, directly or
indirectly, would have to be compiled with the same flags. If the
header is provided as part of a library, then all client code would
have to be compiled with the same flags.

I've seen compiler flags that control whether plain char is signed
or unsigned, and whether pointers are 32 or 64 bits, and such flags
do have to be consistent for all translation units within a program.
But I wouldn't expect an *optimization* flag to affect struct layout.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Beej
Guest
Posts: n/a
 
      06-16-2009
On Jun 15, 10:59*am, Keith Thompson <(E-Mail Removed)> wrote:
> But I wouldn't expect an *optimization* flag to affect struct layout.


I was thinking more "optimize for size", in this case. Like with
gcc's -fpack-struct option. But yeah, I agree it could lead to all
kinds of interesting stuff.

-Beej
 
Reply With Quote
 
Beej
Guest
Posts: n/a
 
      06-16-2009
On Jun 15, 10:26*am, Ben Bacarisse <(E-Mail Removed)> wrote:
> Bit fields have huge problems, but they have fewer problems than they
> are often portrayed as having!


comp.lang.c.bitfields.die.die.die! No, I don't really have a
problem with them in general (you can save tons of space if you're
allocating a pile of structs), but in this particular case with the
packet data, I still think it's more trouble than it's worth trying to
get the struct to line up properly and portably.

-Beej
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
What is the point of having 16 bit colour if a computer monitor can only display 8 bit colour? How do you edit 16 bit colour when you can only see 8 bit? Scotius Digital Photography 6 07-13-2010 03:33 AM
64 bit - Windows Liberty 64bit, Windows Limited Edition 64 Bit, Microsoft SQL Server 2000 Developer Edition 64 Bit, IBM DB2 64 bit - new ! vvcd Computer Support 0 09-17-2004 08:15 PM
bit fields in a structure Hetal C Programming 2 05-22-2004 01:32 AM
bit fields in a structure Eric Sosman C Programming 2 04-21-2004 05:58 PM
64 bit - Windows Liberty 64bit, Windows Limited Edition 64 Bit,Microsoft SQL Server 2000 Developer Edition 64 Bit, IBM DB2 64 bit - new! Ionizer Computer Support 1 01-01-2004 07:27 PM



Advertisments