This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Using array_length macro outside function
- From: Florian Weimer <fweimer at redhat dot com>
- To: TAMUKI Shoichi <tamuki at linet dot gr dot jp>
- Cc: libc-alpha at sourceware dot org
- Date: Mon, 04 Feb 2019 15:34:09 +0100
- Subject: Re: Using array_length macro outside function
- References: <201902040553.AA04223@tamuki.linet.gr.jp>
* TAMUKI Shoichi:
> [1] to calculate the number of elements in the array.
>
> [1] https://sourceware.org/ml/libc-alpha/2017-10/msg01054.html
>
> Now, I tried to further improve this as patched below;
>
> ----------------------------------------------------------------------
> diff --git a/time/tst-strftime2.c b/time/tst-strftime2.c
> index 57d2144..6c2d359 100644
> --- a/time/tst-strftime2.c
> +++ b/time/tst-strftime2.c
> @@ -25,8 +25,10 @@
> #include <string.h>
>
> static const char *locales[] = { "ja_JP.UTF-8", "lo_LA.UTF-8", "th_TH.UTF-8" };
> +#define nlocales array_length (locales)
> +static char ref[nlocales][nformats][ndates][100];
The other problem is that array_length (locales) is not a constant
expression because a statement expression is never a constant
expression. I had not considered these problems when I wrote the
array_length macro.
I would like to retain the verification that the macro argument is not a
pointer. What do you think about the patch below?
Thanks,
Florian
array_length: Make usable as a constant expression
Do not use a statement expression and _Static_assert in array_length,
so that array_length can be used at file scope and as a constant
expression.
The compiler error message looks like this, so this is still
acceptable:
t.c:3:28: error: zero width for bit-field ‘ARGUMENT_NOT_AN_ARRAY’
0 * sizeof (struct { int ARGUMENT_NOT_AN_ARRAY: \
^~~~~~~~~~~~~~~~~~~~~
t.c:10:7: note: in expansion of macro ‘array_length’
int b[array_length (c) + 1];
^~~~~~~~~~~~
2019-02-04 Florian Weimer <fweimer@redhat.com>
* include/array_length.h (array_length): Do not use a statement
expression and _Static_assert, so that array_length can be used at
file scope and as a constant expression.
diff --git a/include/array_length.h b/include/array_length.h
index 65f583063d..cee8897ba7 100644
--- a/include/array_length.h
+++ b/include/array_length.h
@@ -21,13 +21,11 @@
/* array_length (VAR) is the number of elements in the array VAR. VAR
must evaluate to an array, not a pointer. */
-#define array_length(var) \
- __extension__ ({ \
- _Static_assert (!__builtin_types_compatible_p \
- (__typeof (var), __typeof (&(var)[0])), \
- "argument must be an array"); \
- sizeof (var) / sizeof ((var)[0]); \
- })
+#define array_length(var) \
+ (sizeof (var) / sizeof ((var)[0]) \
+ + 0 * sizeof (struct { int ARGUMENT_NOT_AN_ARRAY: \
+ 1 - (__builtin_types_compatible_p \
+ (__typeof (var), __typeof (&(var)[0]))); }))
/* array_end (VAR) is a pointer one past the end of the array VAR.
VAR must evaluate to an array, not a pointer. */