struct compatibility

C

Christian Kandeler

Hi,

I'd like to know whether the following code is standard-compliant:


struct generic {
int x;
int a[1];
};


void f(struct generic *s)
{
int i;

for (i = 0; i < 10; i++)
s->a = i;
}


int main(void)
{
struct special {
int x;
int a[10];
} s;

f((struct generic *) &s);

return 0;
}


Thanks,
Christian
 
M

Marc Boyer

Le 31-01-2006 said:
Hi,

I'd like to know whether the following code is standard-compliant:


struct generic {
int x;
int a[1];
};


void f(struct generic *s)
{
int i;

for (i = 0; i < 10; i++)
s->a = i;
}


int main(void)
{
struct special {
int x;
int a[10];
} s;

f((struct generic *) &s);

return 0;
}


Interesting question...
If s was allocated on the heap, in C99, I think the code
would be standart because of compatibility with flexible
array member.

The standart says that, 6.7.2.1/16-18, if there exist
struct s {
int x;
int a[]; // No size !
};

Then, generic and s are 'compatible' when allocated
with malloc, and also are special and s.
In your example, there is no s, but I do not think
it will create any difference for compilers.


Marc Boyer
 
M

Michael Mair

Christian said:
Hi,

I'd like to know whether the following code is standard-compliant:


struct generic {
int x;
int a[1];
};

void f(struct generic *s)
{
int i;

for (i = 0; i < 10; i++)
s->a = i;
}

int main(void)
{
struct special {
int x;
int a[10];
} s;

f((struct generic *) &s);

return 0;
}


No, it is not. Do you want a C99 or C89 answer?
Essentially, offsetof(struct generic, a) needs not
be equal to offsetof(struct special, a)...

BTW:
struct special {
struct generic access_me;
int a[10 - ((sizeof (struct generic) - offsetof(struct generic,
a))/sizeof (int))];
} s;
(with <stddef.h> included) gives you essentially the struct hack,
so you have no "additional badness" related to other struct layout.
The struct hack, even though not covered by the standard, works
presumably on all known implementations.

Cheers
Michael
 
C

Christian Kandeler

Michael said:
Christian said:
I'd like to know whether the following code is standard-compliant:

struct generic {
int x;
int a[1];
};

void f(struct generic *s)
{
int i;

for (i = 0; i < 10; i++)
s->a = i;
}

int main(void)
{
struct special {
int x;
int a[10];
} s;

f((struct generic *) &s);

return 0;
}


No, it is not. Do you want a C99 or C89 answer?
Essentially, offsetof(struct generic, a) needs not
be equal to offsetof(struct special, a)...


Okay. But if I use a flexible array:

struct generic {
int x;
int a[];
}

is the offset the same, then? I'm not sure if I can deduce that from the
standard. If it is, does that make the rest of the code legal?


Christian
 
C

Christian Bau

Christian Kandeler said:
Michael said:
Christian said:
I'd like to know whether the following code is standard-compliant:

struct generic {
int x;
int a[1];
};

void f(struct generic *s)
{
int i;

for (i = 0; i < 10; i++)
s->a = i;
}

int main(void)
{
struct special {
int x;
int a[10];
} s;

f((struct generic *) &s);

return 0;
}


No, it is not. Do you want a C99 or C89 answer?
Essentially, offsetof(struct generic, a) needs not
be equal to offsetof(struct special, a)...


Okay. But if I use a flexible array:

struct generic {
int x;
int a[];
}

is the offset the same, then? I'm not sure if I can deduce that from the
standard. If it is, does that make the rest of the code legal?


With a flexible array, the offset if a is the same as the offset in
_some_ variant of the struct with fixed array size. Lets say the
compiler chooses one offset when the array size is < 10 and another one
if array size is >= 10, and no other offset, then the offset in the
flexible struct is one of those two offsets. But you don't know which
one.

The other difference is that with any fixed size array, the compiler can
assume that the index is within the bounds. If you use a fixed size
array of size 1, then the compiler can legally ignore the index you pass
and always access array element 0, because that is the only one that you
could access legally. With the flexible size array, the compiler must
produce code that works no matter how large the array is. So here you
have an improvement.
 
M

Marc Boyer

Le 01-02-2006 said:
Michael said:
Christian said:
I'd like to know whether the following code is standard-compliant:

struct generic {
int x;
int a[1];
};

void f(struct generic *s)
{
int i;

for (i = 0; i < 10; i++)
s->a = i;
}

int main(void)
{
struct special {
int x;
int a[10];
} s;

f((struct generic *) &s);

return 0;
}


No, it is not. Do you want a C99 or C89 answer?
Essentially, offsetof(struct generic, a) needs not
be equal to offsetof(struct special, a)...


Okay. But if I use a flexible array:

struct generic {
int x;
int a[];
}

is the offset the same, then? I'm not sure if I can deduce that from the
standard. If it is, does that make the rest of the code legal?


No. There was a restriction I had not seen at first glance 6.7.2.1/17.
"Assuming that all array membres are aligned the same".

You should malloc s or add some code like
assert( offsetof(generic, a) == offsetof(special, a) ).


Marc Boyer
 
B

Barry Schwarz

Hi,

I'd like to know whether the following code is standard-compliant:


struct generic {
int x;
int a[1];
};


void f(struct generic *s)
{
int i;

for (i = 0; i < 10; i++)
s->a = i;
}


int main(void)
{
struct special {
int x;
int a[10];
} s;

f((struct generic *) &s);


The standard guarantees that all pointers to struct have the same
representation. Therefore, casting the value of &s will produce a
representable result. It probably won't even change the
representation.

However, there is no guarantee that a struct special and a struct
generic have the same alignment. If a struct generic has a more
restrictive alignment that the struct special s does not meet, any
attempt to dereference the address, as is done in function f, results
in undefined behavior.

Furthermore, the compiler is allowed to insert different quantities of
padding between i and a in the two different structure types. It is
therefore possible that function f is storing its values in padding of
struct special s (if a struct special has the extra padding) or beyond
the end of struct special s (if a struct generic has the extra
padding). I'm not sure about the first but the second definitely
invokes undefined behavior.

Since it is possible for a compliant compiler to produce this
undefined behavior, the answer has to be the code is not compliant.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,175
Messages
2,570,942
Members
47,489
Latest member
BrigidaD91

Latest Threads

Top