bitfield in struct and padding

S

Stanley Rice

Dear all

Here I declare a structure as follows:

struct flag
{
unsigned int a : 8; /* 1 - 7 is yield the same result*/
char b;
char c;
char d;
};

and sizeof(struct flag) equals 4, which is intuitive.

But when I make a little modification, where the bitwidth allocated to
a is 9:

struct flag
{
unsigned int a : 9; /* modification here */
char b;
char c;
char d;
};

and sizeof(struct flag) equals 8, but not 5, where variable 2 bytes
are allocated to variable a, and 3 bytes are allocated to the
following char type variable.

I want to know how many bytes are allocated to variable a? and how the
padding in the obove structure performs.
 
T

tom st denis

Dear all

Here I declare a structure as follows:

struct flag
{
    unsigned int    a : 8; /* 1 - 7 is yield the same result*/
    char            b;
    char            c;
    char            d;

};

and sizeof(struct flag) equals 4, which is intuitive.

But when I make a little modification, where the bitwidth allocated to
a is 9:

struct flag
{
    unsigned int    a : 9; /* modification here */
    char            b;
    char            c;
    char            d;

};

and sizeof(struct flag) equals 8, but not 5, where variable 2 bytes
are allocated to variable a, and 3 bytes are allocated to the
following char type variable.

I want to know how many bytes are allocated to variable a? and how the
padding in the obove structure performs.

That's more of a compiler question than anything. Chances are good
you're on a 32 or 64-bit host where it is optimizing the structure by
padding it out to 32-bits, then adding padding to the structure as a
whole.

There are usually [per-compiler] pragmas to be had to pack structure
densely. They're not portable.

From experience, if you are using bit-fields it's probably because

a) You're writing non-portable code that talks to hardware

or

b) You're trying to avoid having to use & operators explicitly in your
code when dealing with truncated values...

Personally I've never used bitfields in anything I've written in the
19 years I've been using C [both as an amateur and a pro]...

Tom
 
B

Ben Bacarisse

Stanley Rice said:
Here I declare a structure as follows:

struct flag
{
unsigned int a : 8; /* 1 - 7 is yield the same result*/
char b;
char c;
char d;
};

and sizeof(struct flag) equals 4, which is intuitive.

But when I make a little modification, where the bitwidth allocated to
a is 9:

struct flag
{
unsigned int a : 9; /* modification here */
char b;
char c;
char d;
};

and sizeof(struct flag) equals 8, but not 5, where variable 2 bytes
are allocated to variable a, and 3 bytes are allocated to the
following char type variable.

I want to know how many bytes are allocated to variable a? and how the
padding in the obove structure performs.

I don't think there is a simple way to find out. It must be more than 1
on machine with CHAR_BIT==8, but other than that all you can tell is
where 'b' is. If, say, offsetof(struct flag, b) == 4, you can't tell if
this is due to padding or the size of the unit used to hold 'a', but
does it matter?

More to the point, what is the reason you need to know? What are you
trying to achieve? If your objective is to control the layout, your
compiler may provide non-standard ways to do that. But even so, I'd
want to know the ultimate objective, because there may be better ways to
achieve it.
 
M

Malcolm McLean

Dear all

Here I declare a structure as follows:

struct flag
{
    unsigned int    a : 8; /* 1 - 7 is yield the same result*/
    char            b;
    char            c;
    char            d;

};

and sizeof(struct flag) equals 4, which is intuitive.

But when I make a little modification, where the bitwidth allocated to
a is 9:

struct flag
{
    unsigned int    a : 9; /* modification here */
    char            b;
    char            c;
    char            d;

};

and sizeof(struct flag) equals 8, but not 5, where variable 2 bytes
are allocated to variable a, and 3 bytes are allocated to the
following char type variable.

I want to know how many bytes are allocated to variable a? and how the
padding in the obove structure performs.
You can easily find out.

struct flag s;
printf("%d %d %d %d\n", (int) (&s.b - &s), (int)(&s.c - &s), (int)
(&s.d - &s), (int) sizeof(s));

That will tell you where the padding has been inserted. Clearly on any
system with 8 bit bytes you will need some padding, since 9 bits can't
fit into a whole number of bytes.
 
J

James Dow Allen

From experience, if you are using bit-fields it's probably because

a) You're writing non-portable code that talks to hardware, or
b) You're trying to avoid having to use & operators explicitly in your
code when dealing with truncated values..., [or]

and I would add
c) taking advantage, in routine(s) you want optimized for
speed, of some compilers which deliver better opcodes when
bitfield is used (True of the Sun 68k 1988 compiler;
Perhaps present-day compilers are so good,
this is no longer a problem), or

d) for better readability, e.g. to write
q->bptr = dval; /* Stmt D1 */
instead of
q->d[FADDR] = q->d[FADDR] & ~MASKFOO \
| dval << FOOSHIF; /* Stmt D2 */
Personally I've never used bitfields in anything I've written in the
19 years I've been using C [both as an amateur and a pro]...

Tom

I can say the same, more-or-less. It is the concern about
portability ease that often leads the coder to avoid them unless
there is a very important benefit.

Looking at my example (d) above, I consider that the first form
has a significant readability win. What do others think?

James Dow Allen
 
T

tom st denis

From experience, if you are using bit-fields it's probably because
a) You're writing non-portable code that talks to hardware, or
b) You're trying to avoid having to use & operators explicitly in your
code when dealing with truncated values..., [or]

and I would add
c) taking advantage, in routine(s) you want optimized for
speed, of some compilers which deliver better opcodes when
bitfield is used (True of the Sun 68k 1988 compiler;
Perhaps present-day compilers are so good,
this is no longer a problem), or

d) for better readability, e.g. to write
    q->bptr = dval;  /* Stmt D1 */
instead of
    q->d[FADDR] = q->d[FADDR] & ~MASKFOO \
            | dval << FOOSHIF; /* Stmt D2 */
Personally I've never used bitfields in anything I've written in the
19 years I've been using C [both as an amateur and a pro]...

I can say the same, more-or-less.  It is the concern about
portability ease that often leads the coder to avoid them unless
there is a very important benefit.

Looking at my example (d) above, I consider that the first form
has a significant readability win.  What do others think?

I'd use a macro....

q->d = SET_D_FIELD(potato);

or something to that effect (I write HW drivers a large part of my day
lately...).

Tom
 
K

Keith Thompson

Malcolm McLean said:
You can easily find out.

struct flag s;
printf("%d %d %d %d\n", (int) (&s.b - &s), (int)(&s.c - &s), (int)
(&s.d - &s), (int) sizeof(s));

I don't believe that will compile. &s.b is of type char*; &s is of type
struct flag*.

Just use the offsetof() macro, defined in <stddef.h>.

Here's a program I just threw together (note that offsetof() can't be
applied to a bit-field).

#include <stdio.h>
#include <stddef.h>

struct flag7
{
unsigned int a : 7;
char b;
char c;
char d;
};

struct flag8
{
unsigned int a : 8;
char b;
char c;
char d;
};


struct flag9
{
unsigned int a : 9;
char b;
char c;
char d;
};

int main(void) {
printf("sizeof (struct flag7) = %d\n", (int)sizeof (struct flag7));
printf(" b at %d\n", (int)offsetof(struct flag7, b));
printf(" c at %d\n", (int)offsetof(struct flag7, c));
printf(" c at %d\n", (int)offsetof(struct flag7, d));

printf("sizeof (struct flag8) = %d\n", (int)sizeof (struct flag8));
printf(" b at %d\n", (int)offsetof(struct flag8, b));
printf(" c at %d\n", (int)offsetof(struct flag8, c));
printf(" c at %d\n", (int)offsetof(struct flag8, d));

printf("sizeof (struct flag9) = %d\n", (int)sizeof (struct flag9));
printf(" b at %d\n", (int)offsetof(struct flag9, b));
printf(" c at %d\n", (int)offsetof(struct flag9, c));
printf(" c at %d\n", (int)offsetof(struct flag9, d));

return 0;
}

On my system, the output is:

sizeof (struct flag7) = 4
b at 1
c at 2
c at 3
sizeof (struct flag8) = 4
b at 1
c at 2
c at 3
sizeof (struct flag9) = 8
b at 2
c at 3
c at 4
 

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

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top