struct hack question

C

Capstar

Hi NG,

Does the following code invoke undefined behaviour? I compiled it and it
runs fine. I think this is fine because I think the last 3 arguments of
struct a are organised in memory the same way as the 3 arguments of
struct b. But if my previous statement isn't true in all cases or on all
platforms or with all compilers, this probably will invoke undefined
behaviour.

Can anyone tell me if I'm right or not?

Thanks in advance,
Mark



#include <stdio.h>

struct a
{
int a;
int b;
char *foo;
long int c;
};

struct b
{
int b;
char *foo;
long int c;
};

int main(void)
{
struct a foo;
struct b *bar;

foo.a = 1;
foo.b = 2;
foo.c = 3;

bar = (struct b*)&foo.b;

bar->b *= bar->c;
bar->foo = "This is a test\n";

printf("foo.a: %d\nfoo.b: %d\nfoo.c: %ld\nfoo.foo: %s\n", foo.a,
foo.b, foo.c, foo.foo);

return 0;
}
 
R

Richard Bos

Capstar said:
Does the following code invoke undefined behaviour? I compiled it and it
runs fine. I think this is fine because I think the last 3 arguments of
struct a are organised in memory the same way as the 3 arguments of
struct b.

You think wrong. The padding bytes need not be the same.
struct a
{
int a;
int b;
char *foo;
long int c;
};

struct b
{
int b;
char *foo;
long int c;
};

For example, they can be layed out like this:

struct a
int a: 2 bytes
int b: 2 bytes
char *foo: 4 bytes
long int c: 4 bytes

struct b:
int b: 2 bytes
padding: 2 bytes /* oops... */
char *foo: 4 bytes
long int c: 4 bytes

Richard
 
C

Capstar

Richard said:
You think wrong. The padding bytes need not be the same.




For example, they can be layed out like this:

struct a
int a: 2 bytes
int b: 2 bytes
char *foo: 4 bytes
long int c: 4 bytes

struct b:
int b: 2 bytes
padding: 2 bytes /* oops... */
char *foo: 4 bytes
long int c: 4 bytes

Richard

Ah right, didn't think of that.
Thanks
Mark
 
P

Peter Nilsson

Richard Bos said:
You think wrong. The padding bytes need not be the same.


For example, they can be layed out like this:

struct a
int a: 2 bytes
int b: 2 bytes
char *foo: 4 bytes
long int c: 4 bytes

struct b:
int b: 2 bytes
padding: 2 bytes /* oops... */
char *foo: 4 bytes
long int c: 4 bytes

Although, an evil spirit inside of me begs to ask, what if the program
checks...

offsetof(a,foo) - offsetof(a,b) == offsetof(b,foo) - offsetof(b,b)

....etc?

I think it's ruled out in that only a pointer to the _first_ member of a
struct can be converted to the corresponding struct pointer meaningfully.
[Possibly alignment of struct objects too?!]

Thoughts anyone?
 
X

xarax

Capstar said:
Hi NG,

Does the following code invoke undefined behaviour? I compiled it and it
runs fine. I think this is fine because I think the last 3 arguments of
struct a are organised in memory the same way as the 3 arguments of
struct b. But if my previous statement isn't true in all cases or on all
platforms or with all compilers, this probably will invoke undefined
behaviour.

Can anyone tell me if I'm right or not?

Thanks in advance,
Mark



#include <stdio.h>

struct a
{
int a;
int b;
char *foo;
long int c;
};

struct b
{
int b;
char *foo;
long int c;
};

int main(void)
{
struct a foo;
struct b *bar;

foo.a = 1;
foo.b = 2;
foo.c = 3;

bar = (struct b*)&foo.b;

bar->b *= bar->c;
bar->foo = "This is a test\n";

printf("foo.a: %d\nfoo.b: %d\nfoo.c: %ld\nfoo.foo: %s\n", foo.a,
foo.b, foo.c, foo.foo);

return 0;
}

As others have indicated, alignment issues will
arise when you merely copy the field definitions to
the containing structure. The only way to get it
absolutely right is to embed the "b" struct within
the "a" struct.

=====================
struct b
{
int b;
char *foo;
long int c;
};

struct a
{
int a;
struct b b;
};
=====================

The embedded "b" struct will be aligned
correctly according to the strictest (largest)
alignment requirement of any of its members.


--
----------------------------
Jeffrey D. Smith
Farsight Systems Corporation
24 BURLINGTON DRIVE
LONGMONT, CO 80501-6906
http://www.farsight-systems.com
z/Debug debugs your Systems/C programs running on IBM z/OS!
Are ISV upgrade fees too high? Check our custom product development!
 
J

Jack Klein

Hi NG,

Does the following code invoke undefined behaviour? I compiled it and it
Yes.

runs fine. I think this is fine because I think the last 3 arguments of
struct a are organised in memory the same way as the 3 arguments of
struct b. But if my previous statement isn't true in all cases or on all
platforms or with all compilers, this probably will invoke undefined
behaviour.

Can anyone tell me if I'm right or not?

Thanks in advance,
Mark



#include <stdio.h>

struct a
{
int a;
int b;
char *foo;
long int c;
};

struct b
{
int b;
char *foo;
long int c;
};

int main(void)
{
struct a foo;
struct b *bar;

foo.a = 1;
foo.b = 2;
foo.c = 3;

bar = (struct b*)&foo.b;

bar->b *= bar->c;
bar->foo = "This is a test\n";

printf("foo.a: %d\nfoo.b: %d\nfoo.c: %ld\nfoo.foo: %s\n", foo.a,
foo.b, foo.c, foo.foo);

return 0;
}

The standard makes a specific guarantee about structure types having
an _initial_ set of members of both the same types and the same names.
The common initial set of members may be accessed via an lvalue of
either type.

There is very specifically no such guarantee about any other alignment
of members, and as Richard already correctly pointed out there a
definite possibility of alignment issues.
 
J

Jack Klein

Richard Bos said:
You think wrong. The padding bytes need not be the same.


For example, they can be layed out like this:

struct a
int a: 2 bytes
int b: 2 bytes
char *foo: 4 bytes
long int c: 4 bytes

struct b:
int b: 2 bytes
padding: 2 bytes /* oops... */
char *foo: 4 bytes
long int c: 4 bytes

Although, an evil spirit inside of me begs to ask, what if the program
checks...

offsetof(a,foo) - offsetof(a,b) == offsetof(b,foo) - offsetof(b,b)

...etc?

I think it's ruled out in that only a pointer to the _first_ member of a
struct can be converted to the corresponding struct pointer meaningfully.
[Possibly alignment of struct objects too?!]

Thoughts anyone?

That just means it might work the way the OP wants it to, at least
some of the time, on such a compiler. Or it might not. Either way,
it does not make the behavior any less undefined as far as the
standard is concerned.

Since the standard specifically defines the one and only case in which
structures may be "aliased", all other possible cases generate
undefined behavior.
 
D

Dave Thompson

(structs with similar members but not starting at beginning)
The standard makes a specific guarantee about structure types having
an _initial_ set of members of both the same types and the same names.

Not quite; 6.5.2.3p5 makes the guarantee about initial members with
the same types (and for bitfields widths), with no requirement about
names, *if* they occur in a union. Since an identically declared
struct must be compatible across t.u.s and might occur in a union in
another t.u. even if it doesn't in this one, in practice you can rely
on structs whose initial members have the same types (and widths).

It may be desirable to use the same names if you intend to store and
access the "same" data, but that's a different question.

It is compatibility of struct or union types *between t.u.s* in 6.2.7
that also requires same member names (and tags). Although I see no
good reason the names should matter, and have never seen them do so.
The common initial set of members may be accessed via an lvalue of
either type.

There is very specifically no such guarantee about any other alignment
of members, and as Richard already correctly pointed out there a
definite possibility of alignment issues.

Concur.

- David.Thompson1 at worldnet.att.net
 

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

Forum statistics

Threads
473,982
Messages
2,570,189
Members
46,735
Latest member
HikmatRamazanov

Latest Threads

Top