Here is a program that type-casts between pointers of type struct shape
, struct rectangle
and struct triangle
.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
enum { RECTANGLE, TRIANGLE, MAX };
struct shape {
int type;
};
struct rectangle {
int type;
int x;
int y;
};
struct triangle {
int type;
int x;
int y;
int z;
};
struct shape *get_random_shape()
{
int type = rand() % MAX;
if (type == RECTANGLE) {
struct rectangle *r = malloc(sizeof (struct rectangle));
r->type = type;
r->x = rand() % 10 + 1;
r->y = rand() % 10 + 1;
return (struct shape *) r;
} else if (type == TRIANGLE) {
struct triangle *t = malloc(sizeof (struct triangle));
t->type = type;
t->x = rand() % 10 + 1;
t->y = rand() % 10 + 1;
t->z = rand() % 10 + 1;
return (struct shape *) t;
} else {
return NULL;
}
}
int main()
{
srand(time(NULL));
struct shape *s = get_random_shape();
if (s->type == RECTANGLE) {
struct rectangle *r = (struct rectangle *) s;
printf("perimeter of rectangle: %d\n", r->x + r->y);
} else if (s->type == TRIANGLE) {
struct triangle *t = (struct triangle *) s;
printf("perimeter of triangle: %d\n", t->x + t->y + t->z);
} else {
printf("unknown shape\n");
}
return 0;
}
Here is the output.
$ gcc -std=c99 -Wall -Wextra -pedantic main.c
$ ./a.out
perimeter of triangle: 22
$ ./a.out
perimeter of triangle: 24
$ ./a.out
perimeter of rectangle: 8
You can see above that the program compiled and ran without any warnings. I am trying to understand if it is valid to type-cast a pointer of struct shape
into struct rectangle
and vice-versa even though both the structs are of different sizes.
If your answer is that this is not valid, then please consider that network programming books routinely typecast between struct sockaddr *
, struct sockaddr_in *
and struct sockaddr_in6 *
pointers depending on the socket family (AF_INET vs. AF_INET6), and then explain why such type cast is okay in case of struct sockaddr *
but not in the above case of struct shape *
. Here is an example of type cast with struct sockaddr *
.
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main()
{
struct addrinfo *ai;
if (getaddrinfo("localhost", "http", NULL, &ai) != 0) {
printf("error\n");
return EXIT_FAILURE;
}
if (ai->ai_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
printf("IPv4 port: %d\n", addr->sin_port);
} else if (ai->ai_family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
printf("IPv6 port: %d\n", addr->sin6_port);
}
return 0;
}
This code compiles and runs fine as well. Moreover, this is the recommended way of writing such programs as per books on socket programming.
$ gcc -std=c99 -D_POSIX_SOURCE -Wall -Wextra -pedantic foo.c
$ ./a.out
IPv6 port: 20480