home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c      Meh, in C you gotta define EVERYTHING      243,242 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 241,270 of 243,242   
   Keith Thompson to BGB   
   Re: Nice way of allocating flexible stru   
   08 Oct 25 14:57:46   
   
   From: Keith.S.Thompson+u@gmail.com   
      
   BGB  writes:   
   > On 10/8/2025 1:35 AM, Kaz Kylheku wrote:   
   >> Jonas Lund of https://whizzter.woorlic.org/ mentioned this   
   >> trick in a HackerNews comment:   
   >> Given:   
   >>    struct S {   
   >>      // ...   
   >>      T A[];   
   >>    };   
   >> Don't do this:   
   >>    malloc(offsetof(S, A) + n * sizeof (T));   
   >> But rather this:   
   >>    malloc(offsetof(S, A[n]));   
   >> It's easy to forget that the second argument of offsetof is a   
   >> designator, not simply a member name.   
   >   
   > This is assuming offsetof and can deal with general expressions (vs   
   > just field names). IIRC, it is only required to work with field names   
   > (and with plain structs).   
      
   I just read that part of the standard, and it's not clear whether   
   the second argument to offsetof() has to be a member name or whether   
   it can be something more elaborate.   
      
   Quoting the N3096 draft of C23, 7.21:   
      
       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   
       subobject (designated by *member-designator*), from the beginning   
       of any object of type *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 *type* defines a new   
       type or if the specified member is a bit-field, the behavior   
       is undefined.   
      
   The requirements imply that the type can be a struct or a union.   
      
   The term "member designator" is not used elsewhere in the standard.   
   If the term to be taken literally, then it has to designate a   
   *member*, not an element of a member.  But the term "subobject",   
   along with the address constant requirement, could imply that it   
   could be an arbitrary sequence of members and array elements.   
      
   But in addition to that, in Kaz's example, n is not a constant   
   expression, so `&(t.member-designator)` is not an address constant   
   and therefore `offsetof(S, A[n])` has undefined behavior.   
      
   Every compiler I've tried handles this "correctly", and I tend to   
   think that a compiler would have to go out of its way not to do so.   
   I'd like to see a future standard make offsetof more flexible,   
   with defined behavior for cases like this.   
      
   The C99 Rationale shows these possible definitions:   
      
       (size_t)&(((s_name*)0)->m_name)   
      
       (size_t)(char*)&(((s_name*)0)->m_name)   
      
   which, if they work, should handle Kaz's example correctly.   
      
   --   
   Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com   
   void Void(void) { Void(); } /* The recursive call of the void */   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca