Rocksolid Light

Welcome to novaBBS (click a section below)

mail  files  register  newsreader  groups  login

Message-ID:  

Ahead warp factor one, Mr. Sulu.


devel / comp.lang.c / Re: container_of macro...

SubjectAuthor
* Re: container_of macro...tylo
`* Re: container_of macro...James Kuyper
 `* Re: container_of macro...Ben Bacarisse
  +* Re: container_of macro...tylo
  |+* Re: container_of macro...Ben Bacarisse
  ||+* Re: container_of macro...Richard Damon
  |||+* Re: container_of macro...Ben Bacarisse
  ||||`* Re: container_of macro...Richard Damon
  |||| `* Re: container_of macro...Ben Bacarisse
  ||||  `- Re: container_of macro...tylo
  |||`- Re: container_of macro...James Kuyper
  ||`- Re: container_of macro...Tim Rentsch
  |+- Re: container_of macro...David Brown
  |`* Re: container_of macro...Andrey Tarasevich
  | `- Re: container_of macro...Tim Rentsch
  `* Re: container_of macro...James Kuyper
   `* Re: container_of macro...Chris M. Thomasson
    `- Re: container_of macro...Chris M. Thomasson

1
Re: container_of macro...

<a642a1b6-a80f-4959-b161-83a99a51d3b1n@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23557&group=comp.lang.c++#23557

  copy link   Newsgroups: comp.lang.c
 by: tylo - Mon, 31 Oct 2022 10:27 UTC

onsdag 17. mars 2021 kl. 06:14:19 UTC+1 skrev Jim:
> to nobody in particular,
>
> the 2 arg version of this macro is junk. it cannot do any type checks.
> linux's version has 3 args,
> lines 20,21 force compiler type checks.
> type is usually 'struct foo' of some flavor,
> member must be in it, and thus has some offset from it.
> no code is generated for the enforcement, and thats cool.
>
>
> scripts/kconfig/list.h
> 19:#define container_of(ptr, type, member) ({ \
> 20- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
> 21- (type *)( (char *)__mptr - offsetof(type,member) );})
> 22-
> 23-

The problem with this approach is that ({ ... }) is not standard C, and typeof becomes standard in C23.
Here is how to write it type safely, even in C89:

#define container_of(ptr, type, member) \
((type*)((char*)(ptr) + 0*sizeof((ptr) == &((type*)0)->member) - offsetof(type, member)))

Re: container_of macro...

<tjq6qo$ncr3$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23564&group=comp.lang.c++#23564

  copy link   Newsgroups: comp.lang.c
 by: James Kuyper - Tue, 1 Nov 2022 04:20 UTC

On 10/31/22 06:27, tylo wrote:
...
> #define container_of(ptr, type, member) \
> ((type*)((char*)(ptr) + 0*sizeof((ptr) == &((type*)0)->member) -
offsetof(type, member)))

(type*)0->member dereferences a null pointer. As a result, such code has
undefined behavior. On many systems it will do precisely what you
expect, but it is not required to do that.

Re: container_of macro...

<87leovszmt.fsf@bsb.me.uk>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23566&group=comp.lang.c++#23566

  copy link   Newsgroups: comp.lang.c
 by: Ben Bacarisse - Tue, 1 Nov 2022 11:06 UTC

James Kuyper <jameskuyper@alumni.caltech.edu> writes:

> On 10/31/22 06:27, tylo wrote:
> ..
>> #define container_of(ptr, type, member) \
>> ((type*)((char*)(ptr) + 0*sizeof((ptr) == &((type*)0)->member) -
> offsetof(type, member)))
>
> (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.

Re: container_of macro...

<75219455-ec54-4d99-9d76-6b123c76172cn@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23567&group=comp.lang.c++#23567

  copy link   Newsgroups: comp.lang.c
 by: tylo - Wed, 2 Nov 2022 14:15 UTC

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.

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.

Re: container_of macro...

<874jvh73di.fsf@bsb.me.uk>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23568&group=comp.lang.c++#23568

  copy link   Newsgroups: comp.lang.c
 by: Ben Bacarisse - Wed, 2 Nov 2022 16:00 UTC

tylo <tylovset@gmail.com> writes:

> 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.
>>
>
> Yes, sizeof is also there to avoid ptr being evaluated twice.
>
> 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.

Compilers are permitted to do what they like with that expression (if it
is in a context where it is evaluated) because it the behaviour is
formally undefined. You can's assume anything about the value.

--
Ben.

Re: container_of macro...

<tju60h$17727$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23569&group=comp.lang.c++#23569

  copy link   Newsgroups: comp.lang.c
 by: David Brown - Wed, 2 Nov 2022 16:31 UTC

On 02/11/2022 15:15, 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.
>
> 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.

That is a big assumption - not one you should rely on.

You can't assume non-optimising compilers (or optimising compilers where
optimisation is not enabled) do any kind of optimisation at all, even
the simplest ones. Equally, you can't assume that they will /not/ do
any given optimisations. I've seen compilers that will do "x = 0 + 1;"
at run-time when optimisations are disabled, and I've seen compilers
that will eliminate unreachable code on the assumption that signed
integer arithmetic never overflows even when optimisations are disabled.

Always write code in a way that will be correct and safe (including no
undefined behaviour) regardless of any optimisations.

Re: container_of macro...

<tju88v$17at8$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23570&group=comp.lang.c++#23570

  copy link   Newsgroups: comp.lang.c
 by: Andrey Tarasevich - Wed, 2 Nov 2022 17:09 UTC

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. It does not depend on any compiler optimizations.

Secondly, the above expression does not evaluate to a "compile time
constant". It doesn't need to and it doesn't really matter what it
evaluates to. It is not evaluated at all. It is there for the sole
purpose of producing an invalid comparison

(ptr) == &((type*)0)->member

and therefore a compiler diagnostic in case of type mismatch.

--
Best regards,
Andrey

Re: container_of macro...

<KoE8L.1189$kCk6.56@fx05.iad>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23571&group=comp.lang.c++#23571

  copy link   Newsgroups: comp.lang.c
 by: Richard Damon - Thu, 3 Nov 2022 01:00 UTC

On 11/2/22 12:00 PM, Ben Bacarisse wrote:
> tylo <tylovset@gmail.com> writes:
>
>> 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.
>>>
>>
>> Yes, sizeof is also there to avoid ptr being evaluated twice.
>>
>> 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.
>
> Compilers are permitted to do what they like with that expression (if it
> is in a context where it is evaluated) because it the behaviour is
> formally undefined. You can's assume anything about the value.
>

The arguement of sizeof is NOT evaluated, (except to compute the
type/size of an array, which isn't done here) and that is NOT an
"optimization, so it can't cause undefined behavior.

The type algerbra still happens, and that is all that matters for
determining of the == will create an error.

Re: container_of macro...

<87eduk6e8b.fsf@bsb.me.uk>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23572&group=comp.lang.c++#23572

  copy link   Newsgroups: comp.lang.c
 by: Ben Bacarisse - Thu, 3 Nov 2022 01:03 UTC

Richard Damon <Richard@Damon-Family.org> writes:

> On 11/2/22 12:00 PM, Ben Bacarisse wrote:
>> tylo <tylovset@gmail.com> writes:
>>
>>> 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.
>>>>
>>>
>>> Yes, sizeof is also there to avoid ptr being evaluated twice.
>>>
>>> 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.
>>
>> Compilers are permitted to do what they like with that expression (if it
>> is in a context where it is evaluated) because it the behaviour is
>> formally undefined. You can's assume anything about the value.
>
> The arguement of sizeof is NOT evaluated,

I never said it was. In fact I made this same point earlier. Also (as
far as I can tell) tylo also knows this. I was addressing a claim tylo
make about what a particular expression evaluates to.

--
Ben.

Re: container_of macro...

<P0F8L.1191$kCk6.380@fx05.iad>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23573&group=comp.lang.c++#23573

  copy link   Newsgroups: comp.lang.c
 by: Richard Damon - Thu, 3 Nov 2022 01:43 UTC

On 11/2/22 9:03 PM, Ben Bacarisse wrote:
> Richard Damon <Richard@Damon-Family.org> writes:
>
>> On 11/2/22 12:00 PM, Ben Bacarisse wrote:
>>> tylo <tylovset@gmail.com> writes:
>>>
>>>> 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.
>>>>>
>>>>
>>>> Yes, sizeof is also there to avoid ptr being evaluated twice.
>>>>
>>>> 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.
>>>
>>> Compilers are permitted to do what they like with that expression (if it
>>> is in a context where it is evaluated) because it the behaviour is
>>> formally undefined. You can's assume anything about the value.
>>
>> The arguement of sizeof is NOT evaluated,
>
> I never said it was. In fact I made this same point earlier. Also (as
> far as I can tell) tylo also knows this. I was addressing a claim tylo
> make about what a particular expression evaluates to.
>

But sizeof returns the size of the type, so sizeof in that expression
will ALWAYS return sizeof(int), as that is the ONLY type that the ==
operator returns in C. If the two parametes of the == operator have
incompatible type, we also get a mandatory diagnostic (which might make
the value mute).

Since the value of sizeof was then multiplied by 0, that part of the
expression will always be 0.

This says the express has the value of:

((type*)((char*)(ptr) - offsetof(type, member)))

(There may be an ineffectual subtraction of a 0 value in the calculation)

Which, if "ptr" is actuall a pointer to the member "member" in a struct
"type", will give you a pointer to the "type" object.

Re: container_of macro...

<tjvf7h$1cuhe$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23574&group=comp.lang.c++#23574

  copy link   Newsgroups: comp.lang.c
 by: James Kuyper - Thu, 3 Nov 2022 04:14 UTC

On 11/1/22 07:06, Ben Bacarisse wrote:
> James Kuyper <jameskuyper@alumni.caltech.edu> writes:
>
>> On 10/31/22 06:27, tylo wrote:
>> ..
>>> #define container_of(ptr, type, member) \
>>> ((type*)((char*)(ptr) + 0*sizeof((ptr) == &((type*)0)->member) -
>> offsetof(type, member)))
>>
>> (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.

I hadn't figured out what the macro was actually supposed to do, and
there was enough distance between the expression and the sizeof, and
enough parenthesis, to confuse me on that point. Sorry for the noise.

Re: container_of macro...

<tjvf8j$1cuhe$2@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23575&group=comp.lang.c++#23575

  copy link   Newsgroups: comp.lang.c
 by: James Kuyper - Thu, 3 Nov 2022 04:15 UTC

On 11/2/22 21:00, Richard Damon wrote:
> On 11/2/22 12:00 PM, Ben Bacarisse wrote:
>> tylo <tylovset@gmail.com> writes:
...
>>> 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.
>>
>> Compilers are permitted to do what they like with that expression (if it
>> is in a context where it is evaluated) because it the behaviour is
>> formally undefined. You can's assume anything about the value.
>>
>
> The arguement of sizeof is NOT evaluated, (except to compute the
> type/size of an array, which isn't done here) and that is NOT an
> "optimization, so it can't cause undefined behavior.

Ben was responding to an incorrect claim about what that expression
would evaluate to if it had not occurred inside a sizeof expression.

Re: container_of macro...

<tjvg1v$1d2ti$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23576&group=comp.lang.c++#23576

  copy link   Newsgroups: comp.lang.c
 by: Chris M. Thomasson - Thu, 3 Nov 2022 04:28 UTC

On 11/2/2022 9:14 PM, James Kuyper wrote:
> On 11/1/22 07:06, Ben Bacarisse wrote:
>> James Kuyper <jameskuyper@alumni.caltech.edu> writes:
>>
>>> On 10/31/22 06:27, tylo wrote:
>>> ..
>>>> #define container_of(ptr, type, member) \
>>>> ((type*)((char*)(ptr) + 0*sizeof((ptr) == &((type*)0)->member) -
>>> offsetof(type, member)))
>>>
>>> (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.
>
> I hadn't figured out what the macro was actually supposed to do, and
> there was enough distance between the expression and the sizeof, and
> enough parenthesis, to confuse me on that point. Sorry for the noise.

It's used a lot in the Linux Kernel. Microsoft has one:

https://learn.microsoft.com/en-us/windows/win32/api/ntdef/nf-ntdef-containing_record

Re: container_of macro...

<tjvg36$1d2ti$2@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23577&group=comp.lang.c++#23577

  copy link   Newsgroups: comp.lang.c
 by: Chris M. Thomasson - Thu, 3 Nov 2022 04:29 UTC

On 11/2/2022 9:28 PM, Chris M. Thomasson wrote:
> On 11/2/2022 9:14 PM, James Kuyper wrote:
>> On 11/1/22 07:06, Ben Bacarisse wrote:
>>> James Kuyper <jameskuyper@alumni.caltech.edu> writes:
>>>
>>>> On 10/31/22 06:27, tylo wrote:
>>>> ..
>>>>> #define container_of(ptr, type, member) \
>>>>> ((type*)((char*)(ptr) + 0*sizeof((ptr) == &((type*)0)->member) -
>>>> offsetof(type, member)))
>>>>
>>>> (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.
>>
>> I hadn't figured out what the macro was actually supposed to do, and
>> there was enough distance between the expression and the sizeof, and
>> enough parenthesis, to confuse me on that point. Sorry for the noise.
>
> It's used a lot in the Linux Kernel. Microsoft has one:
>
> https://learn.microsoft.com/en-us/windows/win32/api/ntdef/nf-ntdef-containing_record
>

Iirc, mainly used in intrusive data-structures.

Re: container_of macro...

<87r0yk3vl5.fsf@bsb.me.uk>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23578&group=comp.lang.c++#23578

  copy link   Newsgroups: comp.lang.c
 by: Ben Bacarisse - Thu, 3 Nov 2022 15:29 UTC

Richard Damon <Richard@Damon-Family.org> writes:

> On 11/2/22 9:03 PM, Ben Bacarisse wrote:
>> Richard Damon <Richard@Damon-Family.org> writes:
>>
>>> On 11/2/22 12:00 PM, Ben Bacarisse wrote:
>>>> tylo <tylovset@gmail.com> writes:
>>>>
>>>>> 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.
>>>>>>
>>>>>
>>>>> Yes, sizeof is also there to avoid ptr being evaluated twice.
>>>>>
>>>>> 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.
>>>>
>>>> Compilers are permitted to do what they like with that expression (if it
>>>> is in a context where it is evaluated) because it the behaviour is
>>>> formally undefined. You can's assume anything about the value.
>>>
>>> The arguement of sizeof is NOT evaluated,
>>
>> I never said it was. In fact I made this same point earlier. Also (as
>> far as I can tell) tylo also knows this. I was addressing a claim tylo
>> make about what a particular expression evaluates to.
>
> But sizeof returns the size of the type, so sizeof in that expression
> will ALWAYS return sizeof(int), as that is the ONLY type that the ==
> operator returns in C. If the two parametes of the == operator have
> incompatible type, we also get a mandatory diagnostic (which might
> make the value mute).
>
> Since the value of sizeof was then multiplied by 0, that part of the
> expression will always be 0.

Yes, the value of the '0*sizeof ...' sub-expression in not the point. Its
purpose is to provoke a diagnostic if 'ptr' is of the wrong type.

I think we have our wires crossed because you seem to be disagreeing
with something, but I can't tell what.

I thought that tylo was making a claim about how &((Type*)0)->member
will be evaluated, and since he or she seems to know that it's not
evaluated in the given context I took the remark to be a general one
about the evaluation of that expression when it is, indeed, evaluated.

My point about /that/ expression is that you can't assume what tylo
seemed to be assuming about its evaluation.

> This says the express has the value of:
>
> ((type*)((char*)(ptr) - offsetof(type, member)))
>
> (There may be an ineffectual subtraction of a 0 value in the calculation)
>
> Which, if "ptr" is actuall a pointer to the member "member" in a
> struct "type", will give you a pointer to the "type" object.

Yes. That version had already been posted (I think). The new post was
to add a type check, hence the zero-valued extra expression.

--
Ben.

Re: container_of macro...

<ddcecccc-332a-4748-924c-7a28b0eadb77n@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23656&group=comp.lang.c++#23656

  copy link   Newsgroups: comp.lang.c
 by: tylo - Wed, 16 Nov 2022 11:38 UTC

I wrote:
> 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.

Sorry about the fuzz I made with this comment, which is was incorrect and pointed out by a few of you.

Just to add, there is an alternative way to write this macro, although I think it is equivalent in the end. Although the 0-dereference is not "protected" by sizeof, it is guaranteed never to be executed and therefore not UB:

#define container_of(ptr, type, member) \
((type*)((char*)(1 ? (ptr) : &((type*)0)->member) - offsetof(type, member)))

Re: container_of macro...

<86iljbc8qw.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23738&group=comp.lang.c++#23738

  copy link   Newsgroups: comp.lang.c
 by: Tim Rentsch - Sat, 19 Nov 2022 14:35 UTC

Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> tylo <tylovset@gmail.com> writes:
>
>> 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.
>>
>> Yes, sizeof is also there to avoid ptr being evaluated twice.
>>
>> 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.
>
> Compilers are permitted to do what they like with that expression (if it
> is in a context where it is evaluated) because it the behaviour is
> formally undefined. You can's assume anything about the value.

Forgive me for making an obvious point here: _shouldn't_ assume
anything about the value. People can make unwarranted assumptions
about the value, and some people do, even though they shouldn't,
and that's the problem.

Re: container_of macro...

<86wn7qbv8j.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=23748&group=comp.lang.c++#23748

  copy link   Newsgroups: comp.lang.c
 by: Tim Rentsch - Sat, 19 Nov 2022 19:27 UTC

Andrey Tarasevich <andreytarasevich@hotmail.com> 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.

1
server_pubkey.txt

rocksolid light 0.9.8
clearnet tor