![]() |
address of static array element as address constant
Hi all,
I'm porting some code that provides compile-time assertions from one compiler to another and ran across what I believe to be compliant code that won't compile using the new compiler. Not naming names here to remove bias - I'm trying to tell if I'm relying on implementation defined behavior or if this is a bug in the new compiler. Consider this stripped down example: #include <stddef.h> struct s { int a[3]; int b; }; void foo(void) { switch(0) {case offsetof(struct s,a[0]):;} } The relevant part of the C standard says that: 7.17 Common definitions <stddef.h> <snip> 3 The macros are <snip> offsetof(type, member-designator) which expands to an integer constant expression that has type size_t, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type). The type and member designator shall be such that given static type t; then the expression &(t.member-designator) evaluates to an address constant. (If the specified member is a bit-field, the behavior is undefined.) It's my feeling that &(t.a[0]) does (can, should) evaluate to an address constant, as the types are all complete. Other compilers (at least two different vendors) are able to evaluate this expression as an address constant. However, the new compiler raises an error 'case expression not constant.' The new compiler is able to properly evaluate the offsetof a or b, but not any element of a. What I'd really like is offsetof c.bar [0].baz, but it seems to choke on any subscripted element. a[0] does work as part of a non-constant expression though, eg printf(offsetof(a[0])) So, what say the language lawyers? br, John |
Re: address of static array element as address constant
John Koleszar wrote:
> ...Consider this stripped down example: > > #include <stddef.h> > struct s { int a[3]; int b; }; > void foo(void) { > switch(0) {case offsetof(struct s,a[0]):;} > } > > The relevant part of the C standard says that: > 7.17 Common definitions <stddef.h> > <snip> > 3 The macros are > <snip> > offsetof(type, member-designator) > which expands to an integer constant expression that has > type size_t, the value of which is the offset in bytes, to the > structure member (designated by member-designator), ... Note that you have not supplied a structure member. What you need is: offsetof(struct s, a) > from the beginning of its structure (designated by type). > The type and member designator shall be such that given > static type t; > then the expression &(t.member-designator) evaluates to > an address constant. (If the specified member is a bit- > field, the behavior is undefined.) > > It's my feeling that &(t.a[0]) does (can, should) evaluate to > an address constant, as the types are all complete. Feel away. Just realise that your feelings are incidental. :-) > Other compilers (at least two different vendors) are able to > evaluate this expression as an address constant. However, > the new compiler raises an error 'case expression not > constant.' The new compiler is able to properly evaluate > the offsetof a or b, but not any element of a. AFAICS, no implementation is required to. > What I'd really like is offsetof c.bar[0].baz, but it seems to > choke on any subscripted element. offsetof(c, bar) + offsetof(<bar's type>, baz) -- Peter |
Re: address of static array element as address constant
Peter Nilsson wrote:
> John Koleszar wrote: > > What I'd really like is offsetof c.bar[0].baz, but it seems to > > choke on any subscripted element. > > offsetof(c, bar) + offsetof(<bar's type>, baz) Er... offsetof(<c's type>, bar) + offsetof(<bar's type>, baz) -- Peter |
Re: address of static array element as address constant
On 2008-07-07, John Koleszar <jkoleszar@on2.com> wrote:
> > Consider this stripped down example: > > #include <stddef.h> > struct s { int a[3]; int b; }; > void foo(void) { > switch(0) {case offsetof(struct s,a[0]):;} > } Have you tried offsetof(struct s, a)? > The relevant part of the C standard says that: > 7.17 Common definitions <stddef.h> > <snip> > 3 The macros are > <snip> > offsetof(type, member-designator) But a[0] is not a member designator. It is the 'a' which is the member designator. > which expands to an integer constant expression that has type size_t, > the value of which is the offset in bytes, to the structure member > (designated by member-designator), from the beginning of its structure > (designated by type). The type and member designator shall be such that > given > static type t; > then the expression &(t.member-designator) evaluates to an address Given t.a[0], the syntax is actually (t.a)[0]. The postfix operator [] has nothing to do with the structure member access; it's operating on a pointer which comes out of the t.a expression. > constant. However, the new compiler raises an error 'case expression not > constant.' Indeed, because the expression contains evaluated pointer dereferencing. The other compiler must be accepting this as an extension. |
Re: address of static array element as address constant
On Sun, 06 Jul 2008 20:08:35 -0700, Peter Nilsson wrote:
> John Koleszar wrote: >> ...Consider this stripped down example: >> >> #include <stddef.h> >> struct s { int a[3]; int b; }; >> void foo(void) { >> switch(0) {case offsetof(struct s,a[0]):;} >> } >> >> The relevant part of the C standard says that: >> 7.17 Common definitions <stddef.h> >> <snip> >> 3 The macros are >> <snip> >> offsetof(type, member-designator) >> which expands to an integer constant expression that has type size_t, >> the value of which is the offset in bytes, to the structure member >> (designated by member-designator), ... > > Note that you have not supplied a structure member. What you need is: > offsetof(struct s, a) > I agree, for the simple definition of structure member. I did consider this clause. I suppose I focused more on the address constant portion of the definition because I couldn't think of an example where, given that member-designator is a simple Member, the controlling expression & (t.member-designator) does not evaluate to an address constant. I assume that the spec is not being redundant, so I read the term "member" a little looser here. Maybe I'm missing something obvious. Can you show me a case that meets the first clause (simple member) but not the second (address constant)? >> from the beginning of its structure (designated by type). The type >> and member designator shall be such that given >> static type t; >> then the expression &(t.member-designator) evaluates to an address >> constant. (If the specified member is a bit- field, the behavior is >> undefined.) >> >> It's my feeling that &(t.a[0]) does (can, should) evaluate to an >> address constant, as the types are all complete. > > Feel away. Just realise that your feelings are incidental. :-) > Sorry, bad choice of words. s/feeling/interpretation/. I'm quite aware that it doesn't make a lick of difference what I think :) >> Other compilers (at least two different vendors) are able to evaluate >> this expression as an address constant. However, the new compiler >> raises an error 'case expression not constant.' The new compiler is >> able to properly evaluate the offsetof a or b, but not any element of >> a. > > AFAICS, no implementation is required to. > Do you mean within the context of offsetof? I still think that &(t.a[0]) is required by the standard to be a valid address constant. From 6.6.9: An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type. The array-subscript [] and member-access . and -> operators, the address & and indirection * unary operators, and pointer casts may be used in the creation of an address constant, but the value of an object shall not be accessed by use of these operators. FWIW, the new compiler does accept the member-access operator in the member-designator operand, just not the array-subscript. Not relevant if member-designator is required to be a simple member, of course. >> What I'd really like is offsetof c.bar[0].baz, but it seems to choke on >> any subscripted element. > > offsetof(c, bar) + offsetof(<bar's type>, baz) Of course, I know the workarounds (or the Right Way, depending on your perspective). Just hoping to keep the syntax more compact, as expanding it obscures the intent, thus requiring a comment and making it even more verbose, not to mention slightly less safe (could silently fail if typeof<s.c> != struct c): ct_assert(offsetof(struct s, c.bar[0].baz)%4==0) vs ct_assert((offsetof(struct s, c) + offsetof(struct c, bar) + offsetof(struct b, baz))%4==0) Gets worse with real names, of course. It's irrelevant as I have to work around the issue anyway, just wanted to give a bigger picture as to what/ why I'm trying to achieve. John |
Re: address of static array element as address constant
On Mon, 2008-07-07 at 12:11 +0000, John Koleszar wrote: > On Sun, 06 Jul 2008 20:08:35 -0700, Peter Nilsson wrote: > > > John Koleszar wrote: > >> ...Consider this stripped down example: > >> > >> #include <stddef.h> > >> struct s { int a[3]; int b; }; > >> void foo(void) { > >> switch(0) {case offsetof(struct s,a[0]):;} > >> } > >> > >> The relevant part of the C standard says that: > >> 7.17 Common definitions <stddef.h> > >> <snip> > >> 3 The macros are > >> <snip> > >> offsetof(type, member-designator) > >> which expands to an integer constant expression that has type size_t, > >> the value of which is the offset in bytes, to the structure member > >> (designated by member-designator), ... > > > > Note that you have not supplied a structure member. What you need is: > > offsetof(struct s, a) > > > > I agree, for the simple definition of structure member. I did consider > this clause. I suppose I focused more on the address constant portion of > the definition because I couldn't think of an example where, given that > member-designator is a simple Member, the controlling expression & > (t.member-designator) does not evaluate to an address constant. I assume > that the spec is not being redundant, so I read the term "member" a > little looser here. Maybe I'm missing something obvious. Can you show me > a case that meets the first clause (simple member) but not the second > (address constant)? > > >> from the beginning of its structure (designated by type). The type > >> and member designator shall be such that given > >> static type t; > >> then the expression &(t.member-designator) evaluates to an address > >> constant. (If the specified member is a bit- field, the behavior is > >> undefined.) > >> > >> It's my feeling that &(t.a[0]) does (can, should) evaluate to an > >> address constant, as the types are all complete. > > > > Feel away. Just realise that your feelings are incidental. :-) > > > > Sorry, bad choice of words. s/feeling/interpretation/. I'm quite aware > that it doesn't make a lick of difference what I think :) > > >> Other compilers (at least two different vendors) are able to evaluate > >> this expression as an address constant. However, the new compiler > >> raises an error 'case expression not constant.' The new compiler is > >> able to properly evaluate the offsetof a or b, but not any element of > >> a. > > > > AFAICS, no implementation is required to. > > > > Do you mean within the context of offsetof? I still think that &(t.a[0]) > is required by the standard to be a valid address constant. From 6.6.9: > > An address constant is a null pointer, a pointer to an lvalue > designating an object of static storage duration, or a pointer to a > function designator; it shall be created explicitly using the unary & > operator or an integer constant cast to pointer type, or implicitly by > the use of an expression of array or function type. The array-subscript > [] and member-access . and -> operators, the address & and indirection > * unary operators, and pointer casts may be used in the creation of an > address constant, but the value of an object shall not be accessed by > use of these operators. > > FWIW, the new compiler does accept the member-access operator in the > member-designator operand, just not the array-subscript. Not relevant if > member-designator is required to be a simple member, of course. > > >> What I'd really like is offsetof c.bar[0].baz, but it seems to choke on > >> any subscripted element. > > > > offsetof(c, bar) + offsetof(<bar's type>, baz) > > Of course, I know the workarounds (or the Right Way, depending on your > perspective). Just hoping to keep the syntax more compact, as expanding > it obscures the intent, thus requiring a comment and making it even more > verbose, not to mention slightly less safe (could silently fail if > typeof<s.c> != struct c): > > ct_assert(offsetof(struct s, c.bar[0].baz)%4==0) > vs > ct_assert((offsetof(struct s, c) > + offsetof(struct c, bar) > + offsetof(struct b, baz))%4==0) > > Gets worse with real names, of course. It's irrelevant as I have to work > around the issue anyway, just wanted to give a bigger picture as to what/ > why I'm trying to achieve. ping... can anyone else weigh in on this, or point me to a more formal definition of member? I didn't see it called out on the glossary with the other formal terms. This issue is is still ambiguous in my mind. Thanks! -- John |
Re: address of static array element as address constant
John Koleszar <jkoleszar@on2.com> writes:
> On Mon, 2008-07-07 at 12:11 +0000, John Koleszar wrote: <snip> >> Of course, I know the workarounds (or the Right Way, depending on your >> perspective). Just hoping to keep the syntax more compact, as expanding >> it obscures the intent, thus requiring a comment and making it even more >> verbose, not to mention slightly less safe (could silently fail if >> typeof<s.c> != struct c): >> >> ct_assert(offsetof(struct s, c.bar[0].baz)%4==0) >> vs >> ct_assert((offsetof(struct s, c) >> + offsetof(struct c, bar) >> + offsetof(struct b, baz))%4==0) >> >> Gets worse with real names, of course. It's irrelevant as I have to work >> around the issue anyway, just wanted to give a bigger picture as to what/ >> why I'm trying to achieve. > > ping... can anyone else weigh in on this, or point me to a more formal > definition of member? I didn't see it called out on the glossary with > the other formal terms. This issue is is still ambiguous in my mind. The advice seems sound and includes a quote from the standard. What you seem to want (offsetof(struct s, c.bar[0].baz)) is clearly not permitted (though it might be provided as an extension, of course) and you have identified the correct way to do it (your second ct_assert example). Messy, but I can't see how you can avoid it. -- Ben. |
Re: address of static array element as address constant
On Tue, 2008-07-15 at 16:07 +0100, Ben Bacarisse wrote: > John Koleszar <jkoleszar@on2.com> writes: > > > On Mon, 2008-07-07 at 12:11 +0000, John Koleszar wrote: > <snip> > >> Of course, I know the workarounds (or the Right Way, depending on your > >> perspective). Just hoping to keep the syntax more compact, as expanding > >> it obscures the intent, thus requiring a comment and making it even more > >> verbose, not to mention slightly less safe (could silently fail if > >> typeof<s.c> != struct c): > >> > >> ct_assert(offsetof(struct s, c.bar[0].baz)%4==0) > >> vs > >> ct_assert((offsetof(struct s, c) > >> + offsetof(struct c, bar) > >> + offsetof(struct b, baz))%4==0) > >> > >> Gets worse with real names, of course. It's irrelevant as I have to work > >> around the issue anyway, just wanted to give a bigger picture as to what/ > >> why I'm trying to achieve. > > > > ping... can anyone else weigh in on this, or point me to a more formal > > definition of member? I didn't see it called out on the glossary with > > the other formal terms. This issue is is still ambiguous in my mind. > > The advice seems sound and includes a quote from the standard. What > you seem to want (offsetof(struct s, c.bar[0].baz)) is clearly not > permitted (though it might be provided as an extension, of course) and > you have identified the correct way to do it (your second ct_assert > example). Messy, but I can't see how you can avoid it. > All of the quotes of the standard in this thread are mine, I'm just having a bit of trouble parsing them. My question wrt section 7.17.3 is whether the spec is being redundant or whether there are two independant clauses in effect. That is, is there a case where for a simple member the expression &(t.member) does not evaluate to an address constant? Aha, now I see it. I've been glossing over the parenthetical '(If the specified member is a bit- field, the behavior is undefined)' which explains the need for the second clause. Sorry for the noise. (Now how do I send an enhancement request to ISO :)) br, John |
| All times are GMT. The time now is 06:30 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.