On Sat, Jul 12, 2025 at 9:19 PM Rob Landley <r...@landley.net> wrote: > > On 7/12/25 07:20, Alejandro Colomar wrote: > > Hi Rob, Elliott, > > > > The C Committee is discussing standardization of ({}). > > > > <https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html> > > Huh, gcc can do lambdas? Didn't know that...
it's how TEMP_FAILURE_RETRY() works. > > It would be interesting to know which implementations support this. And > > also how widely used this is in random code. If you can search in > > Android code, and all the weird implementations you know, it would be > > interesting information to present to the committee. Thanks!! > > Never heard of it. > > I've used "do {blah;} while(0);" on several occasions so you can have an > if (blah) thingy(); else thingy(); where thingy is a macro and the > levels work out right without curly brackets, but this I don't recognize... > > Hmmm, apparently the maxof() and minof() macros in toybox's lib/lib.h > are using that. In 2017 I peeled max() and min() out of the xz code > because it was doing it wrong, and I looked up an implementation that > DIDN'T evaluate the arguments multiple times, because I'd seen it before > (int the kernel among other places) and knew that was possible. it was odd to me that typeof was standardized without ({}), because in my experience they always come together, for exactly this use case. you don't see it in C++ because there you have templates, but "i'd have a non-void function template if this were C++" ends up as "({}) + typeof" in C. > The kernel's been doing the variant I used since 2002: > > https://lwn.net/Articles/983965/ yeah, in the Android source tree, implementations of min/max are some of the most common use cases, but there are almost 200 places using ({}) and there's a surprising variety of different uses. and it's (by eye) only half to two-thirds in conjunction with typeof. for example, something like an inline syscall macro doesn't need typeof (but does need to return a value). macro wrappers for inline assembler and/or compiler builtins are probably the majority of use cases, with TEMP_FAILURE_RETRY()-like "do a thing, return the value on success, or abort on failure" being a fairly sizeable group too. (by strange coincidence, i spent time last week working on <stdbit.h> for bionic, and made heavy use of ({}) plus typeof there.) > https://github.com/mpe/linux-fullhistory/commit/ebe8851e282e3 > > Note that the fullhist tree goes back to 0.0.1 including the old > bitcreeper commits and the patches for each dot release before that. > Linus's current tree starts suddenly in 2012 so it's terrible for > figuring out WHY things happened, it just starts a priori ex cathedra. > > Before that they used "type _x = (x);" instead of typeof(), which... I > have no idea. (off-topic, but __auto_type is the one i only recently learned about [after needing it in practice]: https://gcc.gnu.org/onlinedocs/gcc/Typeof.html) > But "curly brackets in parentheses" is apparently a thing > Linux's kernel.h has been using for min() and max() since... (git > annotate file, git show $HASH, git checkout $HASH^1, git annotate file...) > > $ git show 1012854f47d66 > Author: linus1 <torva...@athlon.transmeta.com> > Date: Thu Aug 16 11:00:00 2001 -0600 > > v2.4.8.4 -> v2.4.9 > ... > - David Miller: "min()/max()" cleanups. Understands signs and sizes. > ... > --- a/include/linux/kernel.h > +++ b/include/linux/kernel.h > @@ -112,6 +112,11 @@ static inline void console_verbose(void) > ((unsigned char *)&addr)[1], \ > ((unsigned char *)&addr)[0] > > +#define min(type,x,y) \ > + ({ type __x = (x), __y = (y); __x < __y ? __x: __y; }) > +#define max(type,x,y) \ > + ({ type __x = (x), __y = (y); __x > __y ? __x: __y; }) > + > > That commit did a big "we have a zillion redundant definitions of > min/max and they're all wrong, let's collate them into one and use it" > cleanup. No seriously, it removed 43 redundant definitions: > > $ git show 1012854f47d66 | grep '^-#define min' | wc -l > 43 "we could have a stdc_min() and stdc_max() if we had ({})" is probably argument enough, given that almost everyone gets these wrong. amusingly i notice that although bionic's <sys/param.h> powerof2() uses ({}) + __auto_type (+ __builtin_add_overflow!), the min()/max() in the same file are just the classic bad implementations: /** Returns the lesser of its two arguments. */ #define MIN(a,b) (((a)<(b))?(a):(b)) /** Returns the greater of its two arguments. */ #define MAX(a,b) (((a)>(b))?(a):(b)) i'll probably fix those to use ({}) even though afaik no-one's complained yet. (despite the lengths we tend to go to to avoid multiple evaluation, i think most c programmers just assume that kind of thing isn't safe and avoid it anyway.) > I have no strong opinion on this construct, but it's another thing the > kernel's been using for a quarter century, which Intel had to add to > brag that ICC could build Linux, and Tinycc for tccboot in 2004, then > llvm... as i've implied, i'm not really sure what typeof is _for_ if you don't have ({}) ... i suspect that's why https://en.cppreference.com/w/c/language/typeof_unqual.html is missing an example :-) > Rob _______________________________________________ Toybox mailing list Toybox@lists.landley.net http://lists.landley.net/listinfo.cgi/toybox-landley.net