address of static array element as address constant

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John Koleszar

    #1

    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
  • Peter Nilsson

    #2
    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

    Comment

    • Peter Nilsson

      #3
      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

      Comment

      • Kaz Kylheku

        #4
        Re: address of static array element as address constant

        On 2008-07-07, John Koleszar <jkoleszar@on2. comwrote:
        >
        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.

        Comment

        • John Koleszar

          #5
          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(offse tof(struct s, c.bar[0].baz)%4==0)
          vs
          ct_assert((offs etof(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

          Comment

          • John Koleszar

            #6
            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(offse tof(struct s, c.bar[0].baz)%4==0)
            vs
            ct_assert((offs etof(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


            Comment

            • Ben Bacarisse

              #7
              Re: address of static array element as address constant

              John Koleszar <jkoleszar@on2. comwrites:
              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(offse tof(struct s, c.bar[0].baz)%4==0)
              >vs
              > ct_assert((offs etof(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(struc t 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.

              Comment

              • John Koleszar

                #8
                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. comwrites:
                >
                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(offse tof(struct s, c.bar[0].baz)%4==0)
                vs
                ct_assert((offs etof(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(struc t 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


                Comment

                Working...