Reputation: 2026
I can explicitly create a struct pointer to allocated memory no problem.
widget *p = malloc(sizeof(widget));
and then access members of p
like p->i
.
But in the following example of allocating memory without declaring a type, I get an error trying to access i
because the type of pointer is void
or char
and not struct
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char c[10];
int i;
double d;
} widget;
int main() {
//two ways to do this. char was convention before void type was introduced
void *p = malloc(sizeof(widget)); //base type void is not a structure or union
//char * p = malloc(sizeof(widget));//base type char is not s structure or union
widget w = {"abc", 9, 3.2};
memcpy(p, &w, sizeof(widget)); //coerced to void * pointers
printf("%d", p->i);// error here trying to access
return 0;
}
This example is from "Effective C" by Robert Seacord. Here is what the book says about the example.
In either case the object pointed to by p has no type until an object is copied into this storage. Once this occurs the object has the effective type of the last object copied into this storage, which imprints the type onto the allocated object. In the following example, the storage referenced by p has an effective type of widget following the call to memcpy.
I tried casting p
to a pointer to widget type but this made no difference.
I am probably misunderstanding or missing something. In the book the only difference is he uses a size variable in the example with no explanation as to what the value of the size should be when creating the void *
pointer.
I assumed it should be of sizeof(widget)
in order to hold a widget. On the memcpy
line he actually uses sizeof(widget)
in the book.
Also the comment //coerced to void * pointers
is from the book and I don't know what it means. The rest of the comments are mine.
Can someone please explain to me why this is not working?
Update: Here are the attempts I made to cast void *
to widget *
after memcpy
//casting attempts
(widget *) p; //no change
widget *q = (widget *) p;
printf("%d", q->i); // works
printf("%d", ((widget *)p)->i); //also works
Upvotes: 1
Views: 271
Reputation: 223553
The so-called “imprinting” of effective type is notional: It is used only as an abstract description to describe how compilers work or may work. No actual recording of the type is made in memory.
You must provide the type that is used to access the object, but writing expressions with that type. For example, it p
is declared void *p
, then the type of p
is void *
regardless of what has been stored at the address it points to, and *p
will always be void
, which cannot be used to access an object. You can convert p
to widget *
by using a cast, (widget *) p
, and then the result of that expression has type widget *
, and you can use it to access an object, as width ((widget *) p)->i
.
(widget *) p; //no change
The cast operator merely produces a value; the result of (widget *) p
is a value that can be used further in an expression, as in an assignment expression like q = (widget *) p
or a printf
like printf("%d\n", ((widget *) p)->i);
. It does not make any change in p
.
Upvotes: 2