Reputation: 630
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
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