By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
464,842 Members | 1,072 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 464,842 IT Pros & Developers. It's quick & easy.

Tail space in struct within struct

P: n/a
Consider the following structures:

struct bar {
int i;
float f;
unsigned char tail[1];
};
struct foo {
struct bar b1;
unsigned char _b1tail[B1N];
struct bar b2;
unsigned char _b2tail[B2N];
};

Can I rely on the order of members such that _b1tail will occupy at
least B1N bytes between b1 and b2?:

&foo->b2 - &foo->b1 >= sizeof(struct bar) + BN

So I can use &foo->b2 as the effective end of _b1tail?

Thanks,
Mike
Nov 14 '05 #1
Share this Question
Share on Google+
3 Replies

P: n/a

"Michael B Allen" <mb*****@ioplex.com> wrote
Consider the following structures:

struct bar {
int i;
float f;
unsigned char tail[1];
};
struct foo {
struct bar b1;
unsigned char _b1tail[B1N];
struct bar b2;
unsigned char _b2tail[B2N];
};

Can I rely on the order of members such that _b1tail will occupy at
least B1N bytes between b1 and b2?:

&foo->b2 - &foo->b1 >= sizeof(struct bar) + BN

So I can use &foo->b2 as the effective end of _b1tail?

Yes, but it is what Denis Ritchie calls an "unwarranted chumminess with the
implementation".
I think that the member array "tail" should be zero-sized, however, to
prevent the compiler inserting a trap at position two.
Nov 14 '05 #2

P: n/a

On Sat, 23 Oct 2004, Malcolm wrote:
"Michael B Allen" <mb*****@ioplex.com> wrote

struct bar {
int i;
float f;
unsigned char tail[1];
};
struct foo {
struct bar b1;
unsigned char _b1tail[B1N];
struct bar b2;
unsigned char _b2tail[B2N];
};

Can I rely on the order of members such that _b1tail will occupy at
least B1N bytes between b1 and b2?:

&foo->b2 - &foo->b1 >= sizeof(struct bar) + BN
Of course you meant something more like

(char*)&foo->b2 - (char*)&foo->b1 >= sizeof(struct bar) + B1N

but following that correction, it's correct; you may assume that.
This is because all struct members come one after another in the order
they're defined in the struct definition.
So I can use &foo->b2 as the effective end of _b1tail?
Yes, but it is what Dennis Ritchie calls an "unwarranted chumminess with
the implementation".


Caveat: It depends what you mean by "use." For example, AFAIK it
invokes undefined behavior to write

((char*)&foo->b2)[-1] = 42; /* modify the "last" byte of |_b1tail| */

because the implementation might have put a padding and/or checksum byte
there, and wantonly changing padding bytes is a Bad Thing. (I could be
wrong about the Standard-mandated effect of changing padding bytes, but
it seems reasonable to me.)
I think that the member array "tail" should be zero-sized, however, to
prevent the compiler inserting a trap at position two.


Bad advice. Last I checked, zero-sized objects were not supported in C.
Maybe if Michael explains what he's really trying to do, a better (more
portable) solution will be reached.

HTH,
-Arthur
Nov 14 '05 #3

P: n/a
On Sat, 23 Oct 2004 12:38:06 -0400, Arthur J. O'Dwyer wrote:
So I can use &foo->b2 as the effective end of _b1tail?


Yes, but it is what Dennis Ritchie calls an "unwarranted chumminess
with the implementation".


Caveat: It depends what you mean by "use." For example, AFAIK it
invokes undefined behavior to write

((char*)&foo->b2)[-1] = 42; /* modify the "last" byte of |_b1tail| */

Maybe if Michael explains what he's really trying to do, a better (more
portable) solution will be reached.


Ok. The tail members are bitmaps that are different sizes depending on
needs. I have a struct with several of these object/bitmap pairs that
I initialize with a function like:

int
bar_init(struct bar *b, void *blim, float f)
{
memset(b, 0, blim - (void *)b);
b->blim = blim;
if (something_init(&b->something, f) == -1) {
return -1;
}
b->tail[0] = 0x01; /* don't use bit 0 */
return 0;
}

So when I call this initializer I need to know the end of the tail so
that my bitset rountines know where to stop. Rather than try to compute
this point I reasoned that provided the order of members is maintained
that the member following the tail is and effective blim.

if (bar_init(&foo->b1, &foo->b2, 1.1) == -1 ||
bar_init(&foo->b2, &foo->b3, 2.2) == -1 ||
bar_init(&foo->b4, foo + 1, 3.3) == -1) {
return -1;
}

So based on what you've said I think I'm ok.

Thanks,
Mike
Nov 14 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.