On Mon, Oct 21, 2019 at 10:18 AM Toke Høiland-Jørgensen <toke@xxxxxxxxxx> wrote: > > Andrii Nakryiko <andriin@xxxxxx> writes: > > > LIBBPF_OPTS is implemented as a mix of field declaration and memset > > + assignment. This makes it neither variable declaration nor purely > > statements, which is a problem, because you can't mix it with either > > other variable declarations nor other function statements, because C90 > > compiler mode emits warning on mixing all that together. > > > > This patch changes LIBBPF_OPTS into a strictly declaration of variable > > and solves this problem, as can be seen in case of bpftool, which > > previously would emit compiler warning, if done this way (LIBBPF_OPTS as > > part of function variables declaration block). > > > > Signed-off-by: Andrii Nakryiko <andriin@xxxxxx> > > --- [...] > > diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h > > index 0fdf086beba7..bf105e9e866f 100644 > > --- a/tools/lib/bpf/libbpf.h > > +++ b/tools/lib/bpf/libbpf.h > > @@ -77,12 +77,13 @@ struct bpf_object_open_attr { > > * bytes, but that's the best way I've found and it seems to work in practice. > > */ > > #define LIBBPF_OPTS(TYPE, NAME, ...) \ > > - struct TYPE NAME; \ > > - memset(&NAME, 0, sizeof(struct TYPE)); \ > > - NAME = (struct TYPE) { \ > > - .sz = sizeof(struct TYPE), \ > > - __VA_ARGS__ \ > > - } > > + struct TYPE NAME = ({ \ > > + memset(&NAME, 0, sizeof(struct TYPE)); \ > > + (struct TYPE) { \ > > + .sz = sizeof(struct TYPE), \ > > Wait, you can stick arbitrary code inside a variable initialisation > block like this? How does that work? Is everything before the (struct > type) just ignored (and is that a cast)? Well, you definitely can still arbitrary code into a ({ }) expression block, that's not that surprising. The surprising bit that I discovered just recently was that stuff like this compiles and works correctly, try it: void *x = &x; printf("%lx == %lx\n", x, &x); So I'm using the fact that variable address is available inside variable initialization block. Beyond that, it's just a fancy, but standard (struct bla){ ... initializer list ...} syntax (it's not a struct initializer syntax, mind you, it's a struct assignment from struct literal). Fancy for sure, but it works and solves problems I mentioned in commit description. > > -Toke >