Started by trying to write a small program to translate basic arithmetic into English, I end up building a binary tree(which is inevitably very unbalanced) to represent the order of evaluations.
First, I wrote
struct expr;
typedef struct{
unsigned char entity_flag; /*positive when the oprd
struct represents an entity
---a single digit or a parenthesized block*/
char oprt;
expr * l_oprd;// these two point to the children nodes
expr * r_oprd;
} expr;
However, to efficiently represent single digits, I prefer
typedef struct{
unsigned char entity_flag;
int ival;
} digit;
Since now the “oprd” feild of each “expr” struct may be either of the above struct-s, I now shall modify their types to
void * l_oprd;
void * r_oprd;
Then there comes the “central question”:
how can you access members through a void pointer?
please see the follow code
#include<stdio.h>
#include<stdlib.h>
typedef struct {
int i1;
int i2;} s;
main(){
void* p=malloc(sizeof(s));
//p->i1=1;
//p->i2=2;
*(int*)p=1;
*((int *)p+1)=2;
printf("s{i1:%d, i2: %d}\n",*(int*)p,*((int *)p+1));
}
The compiler wouldn’t accept the commented version!
Do I have to do it with the cluttered approach above?
please help.
PS: as you have noticed ,each struct-s above possess a field of the name “entity_flag”, thus
void * vp;
...(giving some value to vp)
unsigned char flag=vp->entity_flag;
may extract the flag regardless of what void points to, is this allowed in C? or even “safe” in C?
You can’t access members through
void *pointers. There are ways you could cast it (indeed, you don’t even need to state the case explicitly withvoid *), but even that is the wrong answer.The correct answer is to use
union:You then access an expression like this (given a variable
expr *e):And a digit like this:
Any other solution is a nasty hack, IMO, and most of the casting solutions will risk breaking the “strict aliasing” rules that say that the compiler is allowed to assume that two pointers of different types can’t reference the same memory.
Edit …
If you need to be able to inspect the data itself in order to figure out which member of the union is in use, you can.
Basically, If the top-most fields in two structs are declared the same then they will have the same binary representation. This isn’t just limited to unions, this is true in general across all binaries compiled for that architecture (if you think about it, this is essential for libraries to work).
In unions it is common to pull those out into a separate struct so that it’s obvious what you’re doing, although it’s not required:
In this scheme,
p->base.ID,p->A.ID,p->B.IDare guaranteed to read the same.