Path: csiph.com!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: container_of macro... Date: Sat, 19 Nov 2022 11:27:24 -0800 Organization: A noiseless patient Spider Lines: 54 Message-ID: <86wn7qbv8j.fsf@linuxsc.com> References: <20210309194126.744@kylheku.com> <9bf38715-21be-4679-9613-2fb682455d78n@googlegroups.com> <87leovszmt.fsf@bsb.me.uk> <75219455-ec54-4d99-9d76-6b123c76172cn@googlegroups.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader01.eternal-september.org; posting-host="3a600a3efa6b1d635770a4955b3f9787"; logging-data="3460697"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19zRIf8ynH4Nl1hCbvDVaXiuVbmGfJkJvE=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:Q81B6ZXShrXVmz5xhbuFLufJdps= sha1:aXEmtH8r/EekHlMmwcf96Q3OeAU= Xref: csiph.com comp.lang.c:168288 Andrey Tarasevich writes: > On 11/2/2022 7:15 AM, tylo wrote: > >> tirsdag 1. november 2022 kl. 12:06:17 UTC+1 skrev Ben Bacarisse: >> >>>> (type*)0->member dereferences a null pointer. As a result, such >>>> code has undefined behavior. >>> >>> It's in the unevaluated operand of the sizeof operator. The >>> comparison is there just to provoke type-checking (the main thrust >>> of this subthread) and I imagine the sizeof is there to avoid the >>> implied UB. >>> >>> -- >> Ben. >> >> Yes, sizeof is also there to avoid ptr being evaluated twice. > > No. It is there to inject a dummy comparison into an expression. > >> Although not relevant here as sizeof() doesn't evaluate its >> argument, the expression &((Type*)0)->member evaluates to a >> compile time constant even by non-optimizing compilers, as they >> always do basic constant folding optimizations. > > No, no, and no. > > Firstly, what is a constant expression and what isn't is defined by > the language spec. [...] > > Secondly, the above expression does not evaluate to a "compile time > constant". [...] This response isn't exactly right. Both gcc and clang accept an expression of the form &((Type*)0)->member as a constant expression. In particular, a source file typedef struct { int member; } Type; const int *x = & ((Type*)0)->member; is accepted, in a conforming mode, including -pedantic-errors, and without causing any diagnostics (and indeed the value given to x is a compile-time constant). Such expressions don't /have/ to be constant expressions but they /can/ be constant expressions - the C standard explicitly allows additional forms of constant expressions, beyond those described in the standard, to be accepted by a conforming implementation. Similarly, the value of the expression doesn't /have/ to have any particular value but it /can/ be given the value most people would expect. Certainly it is true that the previously quoted expression /might not/ evaluate to a compile time constant, but saying it /does not/ evaluate to a compile time constant is wrong: sometimes it does, even if under different circumstances it would not.