isimmons
isimmons

Reputation: 2026

Allocate memory without declaring a type and then assign a struct type later

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

Answers (1)

Eric Postpischil
Eric Postpischil

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

Related Questions