to*******@hotmail.com schrieb:
Hello,
I want to do something similar to this:
#include <stdlib.h>
struct coord {
double val;
double err;
};
struct point{
double value;
char foo;
struct coord coords[];
};
Note: C99 demands sizeof (struct point) == offsetof(struct foo, c)
for
struct foo {double value; char foo; struct coord c[1];};
but gcc 3.x chooses the size of struct point such that coords meets the
maximum alignment requirements.
In the case of double, this may be the same.
The gcc crowd holds this to be a defect in the C99 standard;
unfortunately, they removed the description of this particular issue
from the C99 status page but did not state how gcc 4.x behaves.
struct expe{
struct point *pts;
int np;
int nc;
};
struct expe *create_expe(int nc, int np){
struct expe *expe_p;
/* check for NULL omitted for simplicity */
expe_p = malloc(sizeof *expe_p);
expe_p->pts = malloc(np * (sizeof *expe_p->pts
+ nc * sizeof *expe_p->pts->coords));
Structures with flexible array member must not be elements of an array;
this is a constraint violation (c.f. C99, 6.7.2.1#2), i.e. we do not
need to consider np != 1.
Once again, due to your using double, this probably "works" as
"expected" but in the general case gives potentially rise to alignment
issues.
expe_p->np = np;
expe_p->nc = nc;
return expe_p;
}
struct point *point(struct expe *expe_p, int i) {
return (struct point *) (
(char *) expe_p->pts
+ i * (sizeof *expe_p->pts
+ expe_p->nc * sizeof *expe_p->pts->coords)
);
}
int main(void) {
struct expe *expe_p=create_expe(4,100);
point(expe_p,2)->value=3;
point(expe_p,2)->coords[1].val=41;
point(expe_p,2)->coords[1].err=34;
These accesses might fail.
return 0;
}
It compiles wo. warning with gcc 4.1.0 and runs ok but I'm not
sure if the the char foo in points can mess up the alignement
requirements of elements of the pts array.
A safe and correct solution is to declare
struct expe{
struct point **pts_p;
int np;
int nc;
};
where pts_p points to allocated storage equivalent to an array np
of struct point *. You have to allocate storage for the elements of
pts_p to point to separately.
This means more allocations but easier access; i.e.
struct expe *create_expe(int nc, int np){
struct expe *expe_p;
int i;
expe_p = malloc(sizeof *expe_p);
if (expe_p != NULL) {
expe_p->pts_p = malloc(np * sizeof *expe_p->pts_p);
if (expe_p->pts_p != NULL) {
for (i = 0; i < np; i++) {
expe_p->pts_p[i] = malloc(sizeof *(expe_p->pts_p[0])
+ nc * sizeof expe_p->pts_p[0]->coords[0]));
if (expe_p->pts_p[i] == NULL) {
break;
}
}
if (i < np) {
/* error handling omitted */
}
} else {
/* error handling omitted */
}
expe_p->np = np;
expe_p->nc = nc;
}
return expe_p;
}
struct point *point(struct expe *expe_p, int i) {
if (i >= 0 && i < expe_p->np)
return expe_p->pts_p[i];
else
return NULL;
}
or you can replace point(expe_p, i) by expe_p->pts_p[i].
The code above is untested.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.