[Toybox] ({}) proposal for ISO C
enh
enh at google.com
Mon Jul 14 07:15:42 PDT 2025
On Sat, Jul 12, 2025 at 9:19 PM Rob Landley <rob at 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 <torvalds at 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
More information about the Toybox
mailing list