C union assignment - c

I have union that represent some structures that all uint32 type but with different bit-fields. can i do assignment of one union to other like this:
typedef union foo_u
{
// raw
uint32_t foo32;
// interpretation 1
struct
{
uint16_t a;
uint16_t b;
} foo_flavor1;
//interpretation 2
struct
{
uint32_t a : 16;
uint32_t b : 12;
uint32_t c : 4;
} foo_flavor2;
} foo;
foo a;
foo b;
a.foo32 = 10;
b.foo32 = 30;
b=a;
or i have to do the assignment like this:
b.foo32 = a.foo32;

b = a;
It's totally OK to do this.
For structures and unions, assigning one to another of the same type is well-defined by the standard, and it's guaranteed that after the assignment, they should contain exactly the same data (padding excluded, if present).

Related

unions as bit fields inside structures

I have the following:
typedef enum {
green = 0;
orange = 1;
red = 2;
} color;
typedef enum {
proceed = 0;
prepare = 1;
stop = 2;
} state;
typedef union {
color a;
state b;
uint8_t reserved;
} status;
typedef struct {
u32 m : 8;
u32 n : 8;
status var : 8;
u32 res : 8;
} info;
I am seeing a compilation error when I define a structure variable:
error: bit-field 'var' has invalid type.
I would like to pack the structure within the 4 bytes, and make the union of enums as a bit field. Is this possible?
Bit fields are defined and restricted only to data types int, signed int, unsigned int but nit for union type as per C89 or C90 standard. Bit Field, applies both for C/C++, with _Bool type defined in C99
If you already know the layout you want, best to ask for it as directly as possible. Probably something like:
typedef struct {
uint8_t m;
uint8_t n;
uint8_t var;
uint8_t res;
} info;
Use an explicitly sized type if you want a particular size. An enum type or union containing a member of enum type is allowed to be (at least) the same size as int, so your desire for this specific layout rules that out.

Assign an integer value to a struct

I have a struct defined as:
typedef struct {
uint8_t field1 : 6,
uint8_t field2 : 1,
uint8_t field3 : 1
} myStruct;
and then:
myStruct s;
What is a safe way to assign an 8-bit value to all the fields at once, i.e.:
s = 10;
The compiler gives error when trying to assign like this (obviously, I'm not even implying this is the way to do it :) ).
Would this be recommended:
uint8_t a = 10;
s = * ((myStruct*) &a);
?
You can use a union:
union myUnion {
struct myStruct ms;
uint8_t byte;
};
myUnion u;
u.byte = 10; /* Uses the same memory as myStruct and its fields. */
printf("field1=%u field2=%u field3=%u\n", u.ms.field1, u.ms.field2, u.ms.field3);
This used to be frowned upon, but see #mafso's comment below, it seems to be allowed now.
you can't assign values to the structure elements like this-
myStruct s;
s = 10;
It is Not allowed. It is not a correct way to do the things!
When you do like below-
uint8_t a = 10;
s = * ((myStruct*) &a);
It is not a safe way to allocate the value 10 to the bit field members! So do it individually like-
s.field1=xx; // Instead of xx, yy and zz assign values
s.field2=yy;
s.field3=zz;
It is the best way to do it!

Is it possible and correct to form union from bit-field in C?

I have the following union and it works correct:
#pragma pack(1)
...
union
{
uint8_t opcode;
struct
{
uint8_t z : 3;
uint8_t y : 3;
uint8_t x : 2;
};
}opcode;
The size of the union is exactly one byte, according to
printf ("%zu\n", sizeof opcode);
The problem takes place when I try to make a union from the bit-field there:
union
{
uint8_t opcode;
struct
{
uint8_t z : 3;
union
{
uint8_t y : 3;
struct
{
uint8_t p : 2;
uint8_t q : 1;
};
}y;
uint8_t x : 2;
};
}opcode;
The result of
printf ("%zu\n", sizeof opcode);
is 3 bytes. Of course I can workaround this with macros but it is it possible at all?
Your code will declare a 3 byte data structure because, as Klas pointed out already, a struct is always padded to the smallest addressable unit.
But it is possible to do what you want by embedding multiple top-level structs in the union and adding padding whenever necessary:
union {
uint8_t opcode;
struct {
uint8_t z:3;
uint8_t y:3;
uint8_t x:2;
};
struct {
uint8_t:3;
uint8_t p:2;
uint8_t q:1;
};
} opcode;
Note that it is possible to declare bit-fields without a name for padding. This is a standard C language feature.
No, it isn't possible to have structs that are fractions of a byte big.
Rationale:
It must be possible to make a pointer to a struct, and the smallest adressable unit is 1 byte.
Note:
This limitation exists in all compilers that I know. I don't know whether it is actually mandated by the C standard.

Bit-field struct within bit-field struct in C

I'm trying to find another way to create a bit-field structure within a bit-field structure in C.
Somewhat like this:
typedef struct
{
int A : 16;
int B : 16;
} Struct1;
typedef struct
{
int A : 16;
Struct1 B : 32;
} Struct2;
But the C Compiler doesn't like it, and it has to be bit-field.
A friend came up with using unions, but was wondering if someone knows another method besides using unions for this?
Thanks!
If I do this:
typedef struct
{
int A : 16;
int B : 16;
} Struct1;
typedef struct
{
int A : 16;
Struct1 B;
} Struct2;
then
Struct2 abc;
abc.A = 0x1111;
abc.B.A = 0x1123;
abc.B.B = 0x3334;
accepts assignments and can be used like bitfields.
This might be of assistance to you. Ofcourse you have to change the declarations a bit.

Typecasting variable with another typedef

typedef struct {
unsigned char a,
unsigned char b,
unsigned char c
}type_a;
typedef struct {
unsigned char e,
unsigned char f[2]
}type_b;
type_a sample;
sample.a = 1;
sample.b = 2;
sample.c = 3;
How do I typecast it and assign new value like:
sample = (type_b)sample; // syntax error
sample.f[1] = 'a';
You should really try it out yourself.
sample = (type_b)sample; /* Can't cast a structure to
another structure. */
sample.f[1] = 'a'; /* sample is still of type type_a,
and doesn't have an `f` field. */
No - C types are static, which means that sample will always remain of type type_a. However, you can achieve what you want using unions:
union {
type_a as_a;
type_b as_b;
} sample;
sample.as_a.a = 1;
sample.as_a.b = 2;
sample.as_a.c = 3;
sample.as_b.f[1] = 'a';
Note that it is not usual to create an object that is a bare union type like this; normally you would include the union within a struct, that includes a tag so that you know what type the object is at the present time:
struct {
enum { TYPE_A, TYPE_B } type;
union {
type_a as_a;
type_b as_b;
} data;
} sample;
/* sample is a TYPE_A right now */
sample.type = TYPE_A;
sample.data.as_a.a = 1;
sample.data.as_a.b = 2;
sample.data.as_a.c = 3;
/* sample is now a TYPE_B */
sample.type = TYPE_B;
sample.data.as_b.f[1] = 'a';
You can't cast one data type to another incompatible data type. However, the memory is open for you. You can access it as follows:
typedef struct
{
unsigned char a;
unsigned char b;
unsigned char c;
}type_a;
typedef struct
{
unsigned char e;
unsigned char f[2];
}type_b;
type_a sample;
sample.a = 1;
sample.b = 2;
sample.c = 3;
type_b *sample_b = (type_b *) ((void*) &sample);
Try out yourself accessing sample_b->e and sample_b->f and see what happens.
No. You can do it by casting pointers: value_b = *((value_b*)&value_a) or by creating union of those two types.
However you do it, be careful. Structures can have different data alignment and you may get unexpected results.
yes you can copy the value of the type_a into type_b by trying something like
type_b sample_b =*((type_b*)&sample);
or
memcpy(&sample_b,&sample,sizeof(type_a));
Typecasting is nothing but converting an expression of one type to another one. But you seem to be trying to convert the type itself, which is fixed at compile time(variable declaration)
Its not clear the idea behind trying something like this. If you can make it more clear, people would be able to give more insights

Resources