Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #168094 > unrolled thread
| Started by | tylo <tylovset@gmail.com> |
|---|---|
| First post | 2022-10-31 03:27 -0700 |
| Last post | 2022-11-02 21:29 -0700 |
| Articles | 18 — 8 participants |
Back to article view | Back to comp.lang.c
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: container_of macro... tylo <tylovset@gmail.com> - 2022-10-31 03:27 -0700
Re: container_of macro... James Kuyper <jameskuyper@alumni.caltech.edu> - 2022-11-01 00:20 -0400
Re: container_of macro... Ben Bacarisse <ben.usenet@bsb.me.uk> - 2022-11-01 11:06 +0000
Re: container_of macro... tylo <tylovset@gmail.com> - 2022-11-02 07:15 -0700
Re: container_of macro... Ben Bacarisse <ben.usenet@bsb.me.uk> - 2022-11-02 16:00 +0000
Re: container_of macro... Richard Damon <Richard@Damon-Family.org> - 2022-11-02 21:00 -0400
Re: container_of macro... Ben Bacarisse <ben.usenet@bsb.me.uk> - 2022-11-03 01:03 +0000
Re: container_of macro... Richard Damon <Richard@Damon-Family.org> - 2022-11-02 21:43 -0400
Re: container_of macro... Ben Bacarisse <ben.usenet@bsb.me.uk> - 2022-11-03 15:29 +0000
Re: container_of macro... tylo <tylovset@gmail.com> - 2022-11-16 03:38 -0800
Re: container_of macro... James Kuyper <jameskuyper@alumni.caltech.edu> - 2022-11-03 00:15 -0400
Re: container_of macro... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-11-19 06:35 -0800
Re: container_of macro... David Brown <david.brown@hesbynett.no> - 2022-11-02 17:31 +0100
Re: container_of macro... Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-11-02 10:09 -0700
Re: container_of macro... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-11-19 11:27 -0800
Re: container_of macro... James Kuyper <jameskuyper@alumni.caltech.edu> - 2022-11-03 00:14 -0400
Re: container_of macro... "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2022-11-02 21:28 -0700
Re: container_of macro... "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2022-11-02 21:29 -0700
| From | tylo <tylovset@gmail.com> |
|---|---|
| Date | 2022-10-31 03:27 -0700 |
| Subject | Re: container_of macro... |
| Message-ID | <a642a1b6-a80f-4959-b161-83a99a51d3b1n@googlegroups.com> |
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)))
[toc] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2022-11-01 00:20 -0400 |
| Message-ID | <tjq6qo$ncr3$1@dont-email.me> |
| In reply to | #168094 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2022-11-01 11:06 +0000 |
| Message-ID | <87leovszmt.fsf@bsb.me.uk> |
| In reply to | #168101 |
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.
[toc] | [prev] | [next] | [standalone]
| From | tylo <tylovset@gmail.com> |
|---|---|
| Date | 2022-11-02 07:15 -0700 |
| Message-ID | <75219455-ec54-4d99-9d76-6b123c76172cn@googlegroups.com> |
| In reply to | #168103 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2022-11-02 16:00 +0000 |
| Message-ID | <874jvh73di.fsf@bsb.me.uk> |
| In reply to | #168104 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2022-11-02 21:00 -0400 |
| Message-ID | <KoE8L.1189$kCk6.56@fx05.iad> |
| In reply to | #168105 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2022-11-03 01:03 +0000 |
| Message-ID | <87eduk6e8b.fsf@bsb.me.uk> |
| In reply to | #168109 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2022-11-02 21:43 -0400 |
| Message-ID | <P0F8L.1191$kCk6.380@fx05.iad> |
| In reply to | #168110 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2022-11-03 15:29 +0000 |
| Message-ID | <87r0yk3vl5.fsf@bsb.me.uk> |
| In reply to | #168111 |
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.
[toc] | [prev] | [next] | [standalone]
| From | tylo <tylovset@gmail.com> |
|---|---|
| Date | 2022-11-16 03:38 -0800 |
| Message-ID | <ddcecccc-332a-4748-924c-7a28b0eadb77n@googlegroups.com> |
| In reply to | #168116 |
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)))
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2022-11-03 00:15 -0400 |
| Message-ID | <tjvf8j$1cuhe$2@dont-email.me> |
| In reply to | #168109 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2022-11-19 06:35 -0800 |
| Message-ID | <86iljbc8qw.fsf@linuxsc.com> |
| In reply to | #168105 |
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.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2022-11-02 17:31 +0100 |
| Message-ID | <tju60h$17727$1@dont-email.me> |
| In reply to | #168104 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2022-11-02 10:09 -0700 |
| Message-ID | <tju88v$17at8$1@dont-email.me> |
| In reply to | #168104 |
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
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2022-11-19 11:27 -0800 |
| Message-ID | <86wn7qbv8j.fsf@linuxsc.com> |
| In reply to | #168107 |
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.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2022-11-03 00:14 -0400 |
| Message-ID | <tjvf7h$1cuhe$1@dont-email.me> |
| In reply to | #168103 |
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.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2022-11-02 21:28 -0700 |
| Message-ID | <tjvg1v$1d2ti$1@dont-email.me> |
| In reply to | #168112 |
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
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2022-11-02 21:29 -0700 |
| Message-ID | <tjvg36$1d2ti$2@dont-email.me> |
| In reply to | #168114 |
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.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web