Minathe
Minathe

Reputation: 630

Typecasting structure pointers

Hie guys. I am studying structures and pointers using the book called Pointers in C: A Hands on Approach and on page 107, I came across an incomplete example of struct type casting. I tried to make it work by just implementing the function receivedata() ,adding headers and making a few changes.
This is the complete code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct signature
{
    char  sign;
    char version;
};

struct id
{
    char id;
    char platform;
};

struct data
{
    struct id idv;
    struct signature sig;
    char data[100];
};

static void receivedata(struct data *d);
static struct signature *extractsignature(struct data *d);
static struct id *extractid(struct data *d);

int main(int argc, char *argv[])
{
/* Actual line in book is :
*  struct data *img; with no memory allocation or assignment to NULL.
*  Had errors so i allocated memory on the heap before passing the value to 
*  Receivedata(); */
    struct data *img = malloc(sizeof(struct data));

    receivedata(img);

/* Actual line in book is :
 *   struct id *idval = extractid(&img);
 *   struct signature *sig = extractsignature(&img);
 * This is obviously erroneous because &img is a pointer 
 * to a pointer (struct data**) which is not the data type for 
 * the extract functions' argument */
    struct id *idval = extractid(img);
    struct signature *sig = extractsignature(img);

    printf("For signature:\n");
    printf("sign = %c", sig->sign);
    printf(" version = %c\n\n", sig->version);

    printf("For id:\n");
    printf("id = %c", idval->id);
    printf(" platform = %c", idval->platform);

    printf("\ndata = %s", img->data);

    return 0;
}

static struct signature *extractsignature(struct data *d)
{
    struct signature *sig = (struct signature *)d;
    return sig;
}

static struct id *extractid(struct data *d)
{
    struct id *idv = (struct id *)d;
    return idv;
}

static void receivedata(struct data *d)
{
    struct data *dptr = d;
    char *ch = "CODING IS COOL!";

    dptr->sig.sign = 's';
    dptr->sig.version = '1';

    dptr->idv.id = 'i';
    dptr->idv.platform = 'p';

    strncpy(dptr->data, ch, strlen(ch));

    return;
}

What I would like to understand is the casting inside the function extractid() and extraxtsignature() because it seems we are casting struct data * so as to retrieve its individual members. I ran the program and what i get is the value of the first member of struct data for both sig member and id members. Here is the output when struct id comes first in the struct data:

For signature:
sign = i version = p

For id:
id = i platform = p
data = CODING IS COOL!

and this when struct signature is the first element:

For signature:
sign = s version = 1

For id:
id = s platform = 1
data = CODING IS COOL!

and finally, this when char data[100] is the first element:

For signature:
sign = C version = O

For id:
id = C platform = O
data = CODING IS COOL!

May you please explain this type of casting, when to use it and the best practices. Thank you very much.

Upvotes: 1

Views: 100

Answers (1)

phoenix
phoenix

Reputation: 3159

struct data
{
    struct id idv;
    struct signature sig;
    char data[100];
};

For the above definition, the extractid function below is valid and will get right results.

static struct id *extractid(struct data *d)
{
    struct id *idv = (struct id *)d;
    return idv;
}

This is because, struct id is the first member of the struct data. So, when you have struct data *d, the d points to the starting address of struct data and which is same as the starting address of the first member struct id.

So, if you are casting for the first member of the struct, then it is right as per the code you have provided above.

Upvotes: 1

Related Questions