Will the size of bitfield be saved even if assigment is via pointer?

Viewed 70

Let's assume I have

struct foo
{
unsigned int bar : 7;
unsigned int next_field : 1;
}
void funct()
{
struct foo demo;
demo.next_field = 0;
unsigned char *barptr  = (unsigned char *)&demo;
/*1 = 00000001, bar can contain only 7 bits*/
*barptr = 1;
}

since bar is 7 bit where as char is 8 bits, what will happen? Will bar be filled with zeros and next_field contain the 1? Will the result be:

0000000  1
|_____| |_|
  bar

or

0000001  0
|_____| |_|
  bar

or:

0000000  0
|_____| |_|
  bar

I would check using my compiler but I don't know wether this behavior is implementation-defined, in witch case the compiler can be misleading.

3 Answers

6.5.3.2 Address and indirection operators

The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.

You cannot take address of a bit-field. This action is illegal in C.

At this point you are quite brutally crossing borders of clean programming.

unsigned char *barptr  = &foo.bar; /* first version of the question */
unsigned char *barptr  = (unsigned char *)&demo; /* after edit  */

You are using the address of something which is not a char in at least two ways and write it to a pointer to char.

After that using that pointer basically tells the compiler "Here is a char. Honest. Believe me. Trust me. Just write it." Whether or not you do that with a type cast (one of the differences between the two versions) is actually irrelevant.

*barptr = 1;

Any "knowing bitsize of bitfield" which the compiler had before have been flattened by you blatantly lying to the compiler afterwards.

If you want to cleanly write bar via a pointer do it like this

struct foo *demop;
demop = &demo;
demop->bar = 1;

In C it is allowed to modify bytes of an object using a pointer to unsigned char. However, as the layout of a bitfield is implementation-defined, it is implementation-defined what value this will result in. Furthermore, the member bar is not initialized before the bytes are modified, so anything is indeed possible, including a compiler assuming that it should contain garbage, even though the byte that contains the bar member in entirety would be initialized by it.

And if the layout is big-endian, it might even be, although unlikely, that the latter bits of the bitfield would reside at the end of the bytes, so that the values of both next_field and bar would be completely unaffected by the change.

Now, would you initialize it with a default initializer,

struct foo demo = {0};

after

unsigned char *barptr  = (unsigned char *)&demo;
*barptr = 1;

we could say that either bar or next_field could have one bit set, or they would be completely zeroed; and you would have to check the behaviour from the compiler manuals. In Linux for example, the ABI documents specify the bitfield layout for each architecture.

Related