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
Related
I have gone through this very good article
https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule
but I didn't understood of aliasing with union, what I know about aliasing is with char/ unsigned char, which is a compiler exception according to this article. so , how I used to do aliasing with char/ unsigned char is like,
// lets say I have struct blah , having int member non_sense, cmmn_sense, intelligence...
struct blah *foo, *foo2;
unsigned char buffer [512];
foo = (struct blah *) (buffer+0);
//now accessing members
foo->non_sense = -1;
foo->non_snese = 0;
foo->intelligence =1;
// now we can use another struct after that ..
foo2 = (struct blah*) (buffer + sizeof(struct blah));
Please correct me if I am wrong some where :)
Q.So how can I do the same with union?
NOTE I didn't encountered with union much, so I don't know its proper use too.
I have also searched for aliasing with enum, but didn't understood much ,
Q.If possible with enum how will we do that?
Sorry for my English, not that good and please openly suggest correction for my misconception or terminology in my question to correct ...
Yes, almost any pointer (including your examples) is unsafe (except if it accessed by char).
Below is safe (access by char pointer):
struct blah x;
char *y = (char *)&x;
for(size_t i = 0; i < sizeof(x); i++)
printf("[%zu] = %hhd\n", i, y[i];
The correct way is to memcpy buffer into the struct or to have char array as one of the union members.
struct a
{
int a;
short b;
char x[2];
double z[3];
};
union b
{
unsigned char buffer[512];
struct a sa[512/32];
};
double foo(char *x)
{
struct a c;
memcpy(&c, x, sizeof(c));
return c.z[0];
}
double bar(void)
{
union b c;
read_from_uart(&c, 512);
return c.sa[5].z[1];
}
Q.If possible with enum how will we do that?
Enum is an integer. Same rules as for integers.
In C, I have defined following struct:
typedef struct my_struct{
int foo;
my_struct* a;
my_struct* b;
} my_struct;
Now, I have a variable char my_var; that holds either the value "a" or "b".
Question: How to access "my_struct->my_var" where my_var is considered as its actual value (i.e. either as the character a or b) rather than as the "string" my_var?
(Indeed, my compiler throws an error saying that there is no member "my_var" defined in the struct my_struct.)
There's nothing built-in that does this. C has no run-time introspection of structure types; member names only exist at compile time.
You can use a conditional operator:
my_struct *x = my_var == 'a' ? my_struct->a : my_struct->b;
If the actual structure is more complicated (you only used 2 members as a simplified example in the question) you could use a lookup table:
struct offset_map {
char name;
size_t offset;
}[] = {
{'a', offsetof(my_struct, a)},
{'b', offsetof(my_struct, b)}
};
You can then write a function that loops through the table and returns the corresponding offset.
size_t get_offset(char name) {
int size = sizeof(offset_map)/sizeof(*offset_map);
for (int i = 0; i < size; i++) {
if (offset_map[i].name == name) {
return offset_map[i].offset;
}
}
return 0;
}
my_struct *x = (my_struct *)((char *)&my_struct + get_offset(my_var));
Let me point out that for indexing we usually use arrays ;-). IIUC, your use case implies that all members you want to be able to select through the character must be of the same type, here my_struct *. So define an array:
struct my_struct{
int foo;
my_struct* ptrs[255]; /* can index with any char */
};
Now you can happily index with characters:
struct my_struct *sP;
/* initialize sP and *sP... */
struct my_struct *sMemP = sP->ptrs['a'];
You can't transform a char variable into code.
You need to check my_var's value:
if (my_var == 'a')
my_struct->a;
else if (my_var == 'b')
my_struct->b;
else
; // Handle unexpected value?
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.
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!
let's say we have a union:
typedef union someunion {
int a;
double b;
} myunion;
Is it possible to check what type is in union after I set e.g. a=123?
My approach is to add this union to some structure and set uniontype to 1 when it's int and 2 when it's double.
typedef struct somestruct {
int uniontype
myunion numbers;
} mystruct;
Is there any better solution?
Is there any better solution?
No, the solution that you showed is the best (and the only) one. unions are pretty simplistic - they do not "track" what you've assigned to what. All they do is let you reuse the same memory range for all their members. They do not provide anything else beyond that, so enclosing them in a struct and using a "type" field for tracking is precisely the correct thing to do.
C does not automatically keep track of which field in a union is currently in use. (In fact, I believe reading from the "wrong" field results in implementation defined behavior.) As such, it is up to your code to keep track of which one is currently used / filled out.
Your approach to keeping a separate 'uniontype' variable is a very common approach to this, and should work well.
There is no way to directly query the type currently stored in a union.
The only ways to know the type stored in a union are to have an explicit flag (as in your mystruct example), or to ensure that control only flows to certain parts of the code when the union has a known active element.
Depending on the application, if it is a short lived object you may be able to encode the type in the control flow, ie. have separate blocks/functions for both cases
struct value {
const char *name;
myunion u;
};
void throwBall(Ball* ball)
{
...
struct value v;
v.name = "Ball"; v.u.b = 1.2;
process_value_double(&v); //double
struct value v2;
v2.name = "Age";
v2.u.a = 19;
check_if_can_drive(&v2); //int
...
}
void countOranges()
{
struct value v;
v.name = "counter";
v.u.a = ORANGE;
count_objects(&v); //int
}
Warning: the following is just for learning purpose:
You could use some ugly tricks to do so (as long as the data types in your union have different sizes, which is the present case):
#include <stdio.h>
typedef union someunion {
int a;
double b;
} myunion;
typedef struct somestruct {
int uniontype;
myunion numbers;
} mystruct;
#define UPDATE_CONTENT(container, value) if ( \
((sizeof(value) == sizeof(double)) \
? (container.uniontype = ((container.numbers.b = value), 2)) \
: (container.uniontype = ((container.numbers.a = value), 1))))
int main()
{
mystruct my_container;
UPDATE_CONTENT(my_container, 42);
printf("%d\n", my_container.uniontype);
UPDATE_CONTENT(my_container, 37.1);
printf("%d\n", my_container.uniontype);
return (0);
}
But I advise you never do this.
Maybe my variant is helping
struct Table
{
char mas[10];
int width;
int high;
union stat
{
int st;
char v;
} un;
};
Table tble[2];
strcpy(tble[0].mas, "box");
tble[0].high = 12;
tble[0].width = 14;
tble[0].un.v = 'S';
strcpy(tble[1].mas, "bag");
tble[1].high = 12;
tble[1].width = 14;
tble[1].un.st = 40;
//struct Table *ptbl = &tble[0];
//ptbl++;
for (int i = 0; i < 2; i++)
{
void *pt = &tble[i].un;
if(*((char*)pt) == 'S')
sort(put_on_bag_line);
else
sort(put_on_box_line);
}