Reputation: 237
I want to be able to "concat" bytes together, so that if I have bytes 00101
and 010
the result will be 00101010
For this task I have written the following code:
#include <stdio.h>
typedef struct
{
unsigned char bits0to5 : 6;
unsigned char bits5to11 : 6;
unsigned char bits11to15 : 4;
}foo;
typedef union
{
foo bytes_in_one_form;
long bytes_in_other_form : 16;
}bar;
int main()
{
bar example;
/*just in case the problem is that bytes_in_other_form wasn't initialized */
example.bytes_in_other_form = 0;
/*001000 = 8, 000101 = 5, 1111 = 15*/
example.bytes_in_one_form.bits0to5 = 8;
example.bytes_in_one_form.bits5to11 = 5;
example.bytes_in_one_form.bits11to15 = 15;
/*sould be 0010000001011111 = 8287*/
/*NOTE: maybe the printf is wrong since its only 2 bytes and from type long?*/
printf("%d", example.bytes_in_other_form);
/*but number printed is 1288*/
return 0;
}
What have I done wrong? Unions should have all their member share the same memory, and both the struct
and the long
take up exactly 2 bytes.
Note:
For solutions that use entirely different algorithm, please note I need to be able to have the zeros at the start (so for example 8 = 001000
and not 1000
, and the solution should match any number of bytes at any distribution (although understanding what I did wrong in my current algorithm is better) I should also mention I use ANSI C.
Thanks!
Upvotes: 0
Views: 61
Reputation: 24082
This answer applies to the original question, which had:
typedef struct
{
unsigned char bits0to5 : 6;
unsigned char bits5to11 : 6;
unsigned char bits11to15 : 4;
}foo;
Here's what's happening in your specific example (note that the results may vary from one platform to another):
The bit fields are being packed into char
variables. If the next bit field doesn't fit into the current char
, it skips to the next one. Additionally, you have little-endian addressing, so the char
values appear right-to-left in the aliased long
bit field.
So the layout of the structure fields is:
+--------+--------+--------+
|....cccc|..bbbbbb|..aaaaaa|
+--------+--------+--------+
Where aaaaaa
is the first field, bbbbbb
is the second field, cccc
is the third field, and the .
values are padding.
When storing your values, you have:
+--------+--------+--------+
|....1111|..000101|..001000|
+--------+--------+--------+
With zeroes in the pad bits, this becomes:
+--------+--------+--------+
|00001111|00000101|00001000|
+--------+--------+--------+
The other value in the union is aliased to the low-order 16 bits, so the value it picks up is:
+--------+--------+
|00000101|00001000|
+--------+--------+
This is 0x0508
, which in decimal is 1288
as you saw.
If the structure instead uses unsigned long
for the bit field types, then we have:
typedef struct
{
unsigned long bits0to5 : 6;
unsigned long bits5to11 : 6;
unsigned long bits11to15 : 4;
}foo;
In this case, the fields are packed into an unsigned long
as follows:
-----+--------+--------+
.....|11110001|01001000|
-----+--------+--------+
The low-order 16 bits are 0xf148
, which is 61768
in decimal.
Upvotes: 3