[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

Struct wrapper conversion

Lauri Alanko

6/16/2011 8:51:00 AM

Given:

typedef struct { int foo; } Bar;

The following is legal (N869 6.7.2.1#12):

Bar b = { 42 };
int* ip = &bar.foo;
Bar* bp = (Bar*) ip;
assert(bp->foo == 42);

But this, to my understanding, might not be:

int i = 42;
int* ip = &i;
Bar* bp = (Bar*) ip;
assert(bp->foo == 42);

The only practical problem I can think of here is that Bar and int
might have different alignments for some reason.

However, all structs are guaranteed to have the same alignment
(6.2.5#27), so how about the following?

typedef struct { Bar bar; } Baz;

Bar b = { 42 };
Baz* zp = (Baz*) &b;
assert(zp->bar.foo == 42);

At this point, although I'm guessing this isn't strictly conforming, I
can't think of any real-world reason why this wouldn't work.

Anyone?


Lauri
4 Answers

James Kuyper

6/16/2011 11:00:00 AM

0

On 06/16/2011 04:50 AM, Lauri Alanko wrote:
> Given:
>
> typedef struct { int foo; } Bar;
>
> The following is legal (N869 6.7.2.1#12):
>
> Bar b = { 42 };
> int* ip = &bar.foo;
> Bar* bp = (Bar*) ip;
> assert(bp->foo == 42);
>
> But this, to my understanding, might not be:
>
> int i = 42;
> int* ip = &i;
> Bar* bp = (Bar*) ip;
> assert(bp->foo == 42);
>
> The only practical problem I can think of here is that Bar and int
> might have different alignments for some reason.

There's other possibilities, as well. For instance, the natural word
size for a given machine might be too big to be convenient to use as
sizeof(int), but the implementation might choose to pad struct Bar to
the word size. That would allow the use of word-size instructions to
read or write bp->foo, with padding bits incidentally being affected by
such operations. If ip+1 happens to point at some piece of memory that
is already in use for some other reason, or is perhaps simply
inaccessible to your program, this would cause obvious problems.

> However, all structs are guaranteed to have the same alignment
> (6.2.5#27), so how about the following?

6.2.5p27 says that all pointers to structs have the same representation
and alignment requirements; the structs that they point to could have
quite different alignment requirements.
--
James Kuyper

Shao Miller

6/17/2011 8:52:00 PM

0

On 6/16/2011 3:50 AM, Lauri Alanko wrote:
> Given:
>
> typedef struct { int foo; } Bar;
>
> The following is legal (N869 6.7.2.1#12):
>
> Bar b = { 42 };
> int* ip =&bar.foo;
> Bar* bp = (Bar*) ip;
> assert(bp->foo == 42);
>
> But this, to my understanding, might not be:
>
> int i = 42;
> int* ip =&i;
> Bar* bp = (Bar*) ip;
> assert(bp->foo == 42);
>
> The only practical problem I can think of here is that Bar and int
> might have different alignments for some reason.

Agreed. They might have different alignment requirements. The
alignment of 'int' would have to be satisfied by the alignment of 'Bar',
but not vice versa.

>
> However, all structs are guaranteed to have the same alignment
> (6.2.5#27), so how about the following?
>

As Mr. James Kuyper already pointed out, that point is in regards to
pointers. Thus a conversion of a 'struct XXX *' to a 'struct YYY *' is
defined regardless of 'XXX' and 'YYY'; the alignment of the pointer
types is good[6.3.2.3p7]. Same with unions.

> typedef struct { Bar bar; } Baz;
>
> Bar b = { 42 };
> Baz* zp = (Baz*)&b;
> assert(zp->bar.foo == 42);
>
> At this point, although I'm guessing this isn't strictly conforming, I
> can't think of any real-world reason why this wouldn't work.
>
> Anyone?

Same problem. The alignment of 'Bar' would have to be satisfied by the
alignment of 'Baz', but not vice versa. If a 'Bar' could only be at
every 4 bytes and a 'Baz' could only be at every 12 bytes, 'b' might be
at 8 bytes. An implementation might notice such an attempt even at
translation-time, since we can discuss it here by looking at it. :)

Barry Schwarz

6/18/2011 11:47:00 PM

0

On Jun 16, 1:50 am, Lauri Alanko <l...@iki.fi> wrote:
> Given:
>
> typedef struct { int foo; } Bar;
>
> The following is legal (N869 6.7.2.1#12):
>
> Bar b = { 42 };
> int* ip = &bar.foo;

This is not legal since there is no object named bar to take the
address of. Did you mean &b.foo?

> Bar* bp = (Bar*) ip;

This is legal only becuase the value in ip is the address of the first
element of a Bar which is guaranteed to be the address of the Bar
itself and is therefore properly aligned for a Bar*.

> assert(bp->foo == 42);
>
> But this, to my understanding, might not be:
>
> int i = 42;
> int* ip = &i;
> Bar* bp = (Bar*) ip;
> assert(bp->foo == 42);
>
> The only practical problem I can think of here is that Bar and int
> might have different alignments for some reason.
>
> However, all structs are guaranteed to have the same alignment
> (6.2.5#27), so how about the following?
>
> typedef struct { Bar bar; } Baz;
>
> Bar b = { 42 };
> Baz* zp = (Baz*) &b;

This has the same problem. There is no guarantee that a Baz does not
have a more restrictive alignment than a Bar. If it does, then the
assignment to zp could invoke undefined behavior.

> assert(zp->bar.foo == 42);
>
> At this point, although I'm guessing this isn't strictly conforming, I
> can't think of any real-world reason why this wouldn't work.
>
> Anyone?
>
> Lauri

Old Wolf

6/27/2011 1:54:00 AM

0

On Jun 16, 8:50 pm, Lauri Alanko <l...@iki.fi> wrote:
> int i = 42;
> int* ip = &i;
> Bar* bp = (Bar*) ip;
> assert(bp->foo == 42);
>
> The only practical problem I can think of here is that Bar and int
> might have different alignments for some reason.

Another problem might be if Bar has padding after
foo, then bounds-checking on 'bp' might indicate a
pointer pointing to a unit that goes past the end
of allocated memory