I'm wondering if the line preceded by the comment "Is this legal C?" (in the function dumpverts()
at the bottom) is legal C or not:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
struct stvertex
{
double x;
double y;
char tag;
};
struct stmesh
{
size_t nverts;
struct stvertex verts[]; /* flexible array member */
};
void dumpverts(struct stvertex *ptr);
int main(int argc, char **argv)
{
size_t f;
size_t usr_nverts=5; /* this would come from the GUI */
struct stmesh *m = malloc(sizeof(struct stmesh) + usr_nverts*sizeof(struct stvertex));
if(m==NULL) return EXIT_FAILURE;
m->nverts=usr_nverts;
for(f=0;f<m->nverts;f++)
{
m->verts[f].x = f*10.0; /* dumb values just for testing */
m->verts[f].y = f*7.0;
m->verts[f].tag = 'V';
}
dumpverts( &(m->verts[0]) );
return EXIT_SUCCESS;
}
void dumpverts(struct stvertex *ptr) /* Here is were the juice is */
{
size_t f;
/* Is this legal C? */
struct stmesh *themesh = (struct stmesh *)((char *)ptr - offsetof(struct stmesh, verts));
for(f=0;f<themesh->nverts;f++)
{
printf("v[%zu] = (%g,%g) '%c'\n", f, themesh->verts[f].x, themesh->verts[f].y, themesh->verts[f].tag);
}
fflush(stdout);
}
I tend to believe it's legal, but I'm not 100% sure if the strict aliasing rule would permit the cast from char *
to struct stmesh *
like the interesting line in the dumpverts()
function body is doing.
Basically, that line is obtaining the pointer to the struct stmesh
from the pointer to its second member. I don't see any alignment-related potential issues, because the memory for the whole struct stmesh
came from malloc()
, so the beginning of the struct is "suitably aligned". But I'm not sure about the strict aliasing rule, as I said.
If it breaks strict aliasing, can it be made compliant without changing the prototype of the dumpverts()
function?
If you wonder what I want this for, it's mainly for learning where are the limits of offsetof()
. Yes, I know dumpverts()
should be receiving a pointer to struct stmesh
instead. But I'm wondering if obtaining the struct stmesh
pointer programmatically would be possible in a legal way.
foo
, then you will only access it as afoo
or certain other allowed types. If you have somehow calculated a pointer to astruct stmesh
and access it as astruct stmesh
, then the aliasing rules are satisfied. The only question is whether the pointer arithmetic is defined to produce a result that points to thestruct stmesh
. – Debornverts
field to theverts
field (that's why I was subtracting the offsets). This was because my first code actually obtainednverts
directly, rather than the pointer to the struct. However, later I realized it was better to obtain the pointer to the struct. So, just the subtraction of theverts
offset is necessary. I modified the code accordingly. Thanks! – Soembawaastyle
on code before posting it, but I stick to the opinion in the K&R book: consistency is better than the indentation choice. – Soembawa