Suppose i have something like:
In list.h:
//...
#include <stdlib.h>
typedef struct node_s{
struct node_s *next;
struct node_s *prev;
char data[];
}node_t;
void* getDataFromNode(node_t *node){
return(node->data);
}
node_t* newNode(size_t size){
node_t *ret = malloc(sizeof(node_t));
return(ret);
}
//...
In main.c:
#include "list.h"
#include <stddef.h>
typedef struct float_node_s{
struct foo_node_s *next;
struct foo_node_s *prev;
float someFloat;
}float_node_t;
int main(void){
float *f;
float_node_t *node;
//1)
node = (float_node_t*)newNode(sizeof(float_node_t));
if(node == NULL){
return(1);
}
//2)
f = (float*)getDataFromNode((node_t*)node);
return(0);
}
This is something i've seen in a lot of C list/tree/etc. implemenatations.
Am i allowed to do this?
Specifically, can i cast a node_t pointer to a float_node_t pointer and assign it to a float_node_t pointer variable like at 1)? What if i dereference the float_node_t pointer now to access the float stored in it? I guess 2) is already disallowed. Returned pointer points to a char array, it is casted to a float pointer.
C standard says that pointers to different structs have equal representations and alignment requirements, that reordering of struct elements does not happen and that if structs have a common initial sequence, the layout of the inital sequence of those structs will be equal.
So casting the pointers and dereferencing to access the prev/next fields seems fine, but isn't that already a violation of C's strict aliasing rules?
There are quite a few somewhat similar questions about casting pointers between "compatible" structs, but often the answers disagree or even contradict each other. Some say, it is fine to access the fields of the common initial sequence through either pointer, some say you can't even dereference the casted pointer.