bitfields in union : defined behaviour ?

G

gert.vierman

Hello,

Here is some code mixing bitfields and longs in an union.
Any comments on the validity and portability of this program ?
Thank you very much.

#include <stdio.h>

union msg_t {

struct elem {
unsigned long foo: 16;
unsigned long bar: 12;
unsigned long type: 4;
unsigned long length: 32;
} elem;

unsigned long data[2];

} ;

int main(int argc, char **argv)
{
union msg_t msgh;

msgh.elem.bar = 0x2;
msgh.elem.foo = 0x3;
msgh.elem.length = 0x100;

printf("%08x\n", msgh.data[0]);
printf("%08x\n", msgh.data[1]);

return 0;
}
 
G

gert.vierman

Hello,

Here is some code mixing bitfields and longs in an union.
Any comments on the validity and portability of this program ?
Thank you very much.

#include <stdio.h>

union msg_t {

struct elem {
unsigned long foo: 16;
unsigned long bar: 12;
unsigned long type: 4;
unsigned long length: 32;
} elem;

unsigned long data[2];

} ;

int main(int argc, char **argv)
{
union msg_t msgh;

msgh.elem.bar = 0x2;
msgh.elem.foo = 0x3;
msgh.elem.length = 0x100;

printf("%08x\n", msgh.data[0]);
printf("%08x\n", msgh.data[1]);

return 0;
}

I am sorry, all 'unsigned longs' should be replaced by the proper type
which is guaranteed to be an unsigned 32 bits int on all platforms.
maybe uint32_t from stdint.h ?
 
R

Richard Bos

Here is some code mixing bitfields and longs in an union.
Any comments on the validity and portability of this program ?
union msg_t {
struct elem {
unsigned long foo: 16;
unsigned long bar: 12;
unsigned long type: 4;
unsigned long length: 32;
} elem;
unsigned long data[2];
} ;
union msg_t msgh;

msgh.elem.bar = 0x2;
msgh.elem.foo = 0x3;
msgh.elem.length = 0x100;

printf("%08x\n", msgh.data[0]);
printf("%08x\n", msgh.data[1]);

Yes. This is not portable ISO C. Assigning a value to any member of a
union makes all other members take unspecified (maybe even undefined; I
can't remember) values. One reason for this is that you don't know how
your bit fields are arranged inside their parent members.

Richard
 
G

gert.vierman

Richard said:
Here is some code mixing bitfields and longs in an union.
Any comments on the validity and portability of this program ?
union msg_t {
struct elem {
unsigned long foo: 16;
unsigned long bar: 12;
unsigned long type: 4;
unsigned long length: 32;
} elem;
unsigned long data[2];
} ;
union msg_t msgh;

msgh.elem.bar = 0x2;
msgh.elem.foo = 0x3;
msgh.elem.length = 0x100;

printf("%08x\n", msgh.data[0]);
printf("%08x\n", msgh.data[1]);

Yes. This is not portable ISO C. Assigning a value to any member of a
union makes all other members take unspecified (maybe even undefined; I
can't remember) values. One reason for this is that you don't know how
your bit fields are arranged inside their parent members.

Thank you, that is what I already expected.
 
K

Keith Thompson

Here is some code mixing bitfields and longs in an union.
Any comments on the validity and portability of this program ?
Thank you very much.

#include <stdio.h>

union msg_t {

struct elem {
unsigned long foo: 16;
unsigned long bar: 12;
unsigned long type: 4;
unsigned long length: 32;
} elem;

unsigned long data[2];

} ;

int main(int argc, char **argv)
{
union msg_t msgh;

msgh.elem.bar = 0x2;
msgh.elem.foo = 0x3;
msgh.elem.length = 0x100;

printf("%08x\n", msgh.data[0]);
printf("%08x\n", msgh.data[1]);

return 0;
}

Apart from the problems of accessing one member of a union after
storing a value in another member, the only portable types for
bitfields are int, unsigned int, signed int, and (in C99) _Bool.
Implementations may support other types as an extension.

Any bit fields larger than 16 bits are non-portable (since int is only
required to be 16 or more bits).
 
D

dwks

And you shouldn't make a bit field 8 bits or 16 or something -- in
those cases you can just use a char or something.
 
W

William J. Leary Jr.

dwks said:
And you shouldn't make a bit field 8 bits or 16 or something -- in
those cases you can just use a char or something.

I've used :8 to guarantee eight bits.

This was back in pre-ANSI days, with a program running on two platforms, one of
which had nine bit characters. I think I did it to save a lot of masking
operations, which were making the code hard to read. And which someone would
always forget at least one of when adding a new feature.

- Bill
 
K

Keith Thompson

dwks said:
And you shouldn't make a bit field 8 bits or 16 or something -- in
those cases you can just use a char or something.

Please read <http://cfaj.freeshell.org/google/> and follow its advice.

There's no guarantee that a char is 8 bits. There's no guarantee that
8-bit and 16-bit types even exists (I've used a system with no
predefined 16-bit integer type). The only guarantees are:

char >=8
short >=16
int >=16
long >=32
long long >=64 (C99 only)
char <= short <= int <= long <= long long

(I'm using a shorthand notation that should be clear enough, but
doesn't correspond to anything you'd see in a C expression.)
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top