Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: Offsetof with array elements Date: Tue, 18 Feb 2020 01:39:47 -0800 Organization: A noiseless patient Spider Lines: 50 Message-ID: <8636b8fd3w.fsf@linuxsc.com> References: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="d9b0a35ddf05bf8591aa2d3738ff843a"; logging-data="14319"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+m/xcVrr/8JxDs4z1fDNUoJCsevIpVB0A=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:kQT0L0zsWUkP1BDekQQW3ygVxJM= sha1:dl1LG/PkIu0ViZ8f7SfZMPMEsQ4= Xref: csiph.com comp.lang.c:150069 Guillaume writes: > Le 11/02/2020 at 15:31, David Brown a ecrit: > >> #include >> >> struct S { >> int a[10]; >> }; >> >> int test(int i) { >> return offsetof(struct S, a[i]); >> } >> >> >> Is this allowed in standard C? [...] Undefined behavior, as was pointed out downthread, because of a non-constant address calculation. However, leading into the next point, what if the address calculation were suitably constant, and so satisfies the stipulation that "the expression &(t.member-designator) evaluates to an address constant"? > [...] > > There's just a small "but": the standard defines offsetof() with its > second parameter being a struct member designator. a[i] is not, unless > I'm mistaken, a member designator, but an expression derived from > one. Thus you'd be using offsetof() with (IMO) an invalid parameter, > and this should be reasonably rejected by a conforming compiler. It > looks like some compilers choose to make this implementation-defined > instead. Just my opinion on this. A strict reading of the text of the Standard supports this conclusion, even if the array index expression were suitably constant. The Standard consistently uses the term "stucture member" to mean an first-level subobject, and not a sub-subobject for any level beyond the first. The safest course here would use offsetof( struct S, a ) and add in the adjustment for a[i] using sizeof and a multiplication. Probably this reading is not what was intended for offsetof(), but I haven't seen any evidence of that. (Fair disclosure: I haven't made any special effort to find any either.) But a good rule to follow in cases where the Standard isn't 100% definitive is to err on the side of caution, choosing the most conservative path reasonably available. And here that is easy to do, by using the simpler call to offsetof() shown above, and adjusting the result with a sizeof, etc.