PDA

View Full Version : Bit Fields




North Bronson
Nov 7, 2010, 04:42 PM
Hello. If anyone could help me understand how to use these bit-fields, that would be great.

Both of my C texts tell me that I can instantiate a struct like this:

#include <stdio.h>

int main (int argc, char *argv[])
{
struct intStruct
{
unsigned int value0 : 1;
unsigned int value1 : 1;
unsigned int value2 : 1;
unsigned int value3 : 1;
unsigned int value4 : 1;
unsigned int value5 : 1;
unsigned int value6 : 1;
unsigned int value7 : 1;
};

printf("%lu\n", sizeof(struct intStruct));

return 0;
}

The console tells me that this struct is four bytes long. Shouldn't it be only one byte?

If I try this:

#include <stdio.h>

int main (int argc, char *argv[])
{
struct charStruct
{
unsigned char value0 : 1;
unsigned char value1 : 1;
unsigned char value2 : 1;
unsigned char value3 : 1;
unsigned char value4 : 1;
unsigned char value5 : 1;
unsigned char value6 : 1;
unsigned char value7 : 1;
};

printf("%lu\n", sizeof(struct charStruct));

return 0;
}

The console tells me that the struct is only one byte, but both of my C texts tell me not to use chars for bit-fields.

If anyone can explain what's going on, that would be great.



robbieduncan
Nov 7, 2010, 04:56 PM
Why would the size of 8 ints be 1 byte? That would imply each int was only 1 bit so could only represent 2 values. Ints can obviously represent more values than that...

subsonix
Nov 7, 2010, 05:03 PM
The compiler might add padding to make the program faster and more efficient. You can force it to be packed with gcc, which might lead to a less efficient program but anyway. Try this.


#include <stdio.h>

int main (int argc, char *argv[])
{
struct intStruct
{
unsigned int value0 : 1;
unsigned int value1 : 1;
unsigned int value2 : 1;
unsigned int value3 : 1;
unsigned int value4 : 1;
unsigned int value5 : 1;
unsigned int value6 : 1;
unsigned int value7 : 1;
}__attribute__((packed));

printf("%lu\n", sizeof(struct intStruct));

return 0;
}

gnasher729
Nov 7, 2010, 05:04 PM
To get an almost authoritative answer, google for "N1256.pdf" which will find the last free draft of the C99 Standard. From that document:

"A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type."

In other words, while the gcc compiler may accept bitfields of type "unsigned char", other compilers might not. Bit fields of type "unsigned int" are portable.

On the other hand, there is no danger in using bit fields of type char or unsigned char: If the compiler accepts it then it works; if it doesn't work the compiler will tell you, so you can leave it to whoever tries to port the code to make the change (a comment would be nice so that a programmer having to fix a compiler error knows what is going on).

North Bronson
Nov 7, 2010, 05:50 PM
Why would the size of 8 ints be 1 byte? That would imply each int was only 1 bit so could only represent 2 values. Ints can obviously represent more values than that...

I thought that by using bit-fields I could force the compiler to build each int into only one-bit. Isn't that the what bit-fields are supposed to be able to do?

North Bronson
Nov 7, 2010, 05:52 PM
The compiler might add padding to make the program faster and more efficient. You can force it to be packed with gcc, which might lead to a less efficient program but anyway. Try this.


#include <stdio.h>

int main (int argc, char *argv[])
{
struct intStruct
{
unsigned int value0 : 1;
unsigned int value1 : 1;
unsigned int value2 : 1;
unsigned int value3 : 1;
unsigned int value4 : 1;
unsigned int value5 : 1;
unsigned int value6 : 1;
unsigned int value7 : 1;
}__attribute__((packed));

printf("%lu\n", sizeof(struct intStruct));

return 0;
}



Interesting. That code that you added works and the struct is only one byte now.

North Bronson
Nov 7, 2010, 05:54 PM
To get an almost authoritative answer, google for "N1256.pdf" which will find the last free draft of the C99 Standard. From that document:

"A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type."

In other words, while the gcc compiler may accept bitfields of type "unsigned char", other compilers might not. Bit fields of type "unsigned int" are portable.

On the other hand, there is no danger in using bit fields of type char or unsigned char: If the compiler accepts it then it works; if it doesn't work the compiler will tell you, so you can leave it to whoever tries to port the code to make the change (a comment would be nice so that a programmer having to fix a compiler error knows what is going on).

Good to know. I'm building this on Xcode for Snow Leopard (with GCC). I should probably check what LLVM would do with that same struct.

subsonix
Nov 7, 2010, 06:11 PM
I thought that by using bit-fields I could force the compiler to build each int into only one-bit. Isn't that the what bit-fields are supposed to be able to do?

I think the main idea it to provide an easier to use interface then dealing with bitwize operations. It also gives you the added benefit of being able to give meaningful names to the bit positions. You could just as well have used an unsigned char directly if you wanted to.

Also, if something is 1 byte or 4 is less of a concern today and if the compiler thinks it's more efficient to align data in 32 bit boundries it will do so by adding some padding. But as you saw, it's possible to suggest that it should not be done if it's necessary for some reason.