array_length, array_end macros for internal use

Message ID 9c9b0fdf-5b87-7e58-0b0b-c8469e56c0a4@redhat.com
State Superseded
Headers

Commit Message

Florian Weimer Oct. 21, 2017, 3:19 p.m. UTC
  I just encountered yet another case where I had to use the sizeof (A) / 
sizeof (A[0]) idiom, so I wrote a general macro for it, with type 
validation.

I put it into a separate header so that it can be used both from the 
library and (non-internal) tests.

The macro as written is not compatible with C++ because it uses 
__builtin_types_compatible_p for explicitness.  If we need something 
like this in C++ mode, we should write it as a (constexpr) template 
function.

If accepted, I will commit the stdio-common subdirectory conversion 
separately from the header, to simplify backports.

Thanks,
Florian
  

Comments

Paul Eggert Oct. 21, 2017, 6:10 p.m. UTC | #1
Thanks, this is a good thing to write a macro for. A couple of comments:

The Emacs internals use the name ARRAYELTS for the same concept. I recall that 
the name was discussed at some length when the macro was introduced. "length" is 
perhaps not the best word to use here, since array_length ("foo") != strlen 
("foo"). And capitalization is appropriate when a macro cannot be written as a 
function. So I suggest the name ARRAYELTS, or something like it.

> +#define array_end(var) &(var)[array_length (var)]

We haven't felt the need for such a macro in Emacs. If there's need in glibc, 
the definiens should be parenthesized so that (mis?)uses like (& ARRAYEND 
(var)->firstmember) are handled properly.
  
Florian Weimer Oct. 21, 2017, 8:42 p.m. UTC | #2
On 10/21/2017 08:10 PM, Paul Eggert wrote:
> Thanks, this is a good thing to write a macro for. A couple of comments:
> 
> The Emacs internals use the name ARRAYELTS for the same concept. I 
> recall that the name was discussed at some length when the macro was 
> introduced. "length" is perhaps not the best word to use here, since 
> array_length ("foo") != strlen ("foo").

I didn't want to use array_size because of the potential confusion with 
sizeof.

> And capitalization is 
> appropriate when a macro cannot be written as a function. So I suggest 
> the name ARRAYELTS, or something like it.

glibc has not followed this style for some time (see libc_hidden_def, 
__libc_lock_lock etc.), and the C++ version (if we need it) will be 
written as a function anyway.

>> +#define array_end(var) &(var)[array_length (var)]
> 
> We haven't felt the need for such a macro in Emacs.

I saw a couple of uses in stdio-common, so I added it.

> If there's need in 
> glibc, the definiens should be parenthesized so that (mis?)uses like (& 
> ARRAYEND (var)->firstmember) are handled properly.

Thanks, fixed in my local version.

Florian
  
Paul Eggert Oct. 22, 2017, 1:36 a.m. UTC | #3
Florian Weimer wrote:

> I didn't want to use array_size because of the potential confusion with sizeof.

Yes, that's a good reason to avoid that name.

> glibc has not followed this style for some time (see libc_hidden_def, 
> __libc_lock_lock etc.), and the C++ version (if we need it) will be written as a 
> function anyway.

OK, then how about the "arrayelts", or "array_elts"? "array_length" is a bit 
confusion-prone, because "length" is so often one less than the number of elements.
  
Florian Weimer Oct. 22, 2017, 7:14 a.m. UTC | #4
On 10/22/2017 03:36 AM, Paul Eggert wrote:
> Florian Weimer wrote:
> 
>> I didn't want to use array_size because of the potential confusion 
>> with sizeof.
> 
> Yes, that's a good reason to avoid that name.
> 
>> glibc has not followed this style for some time (see libc_hidden_def, 
>> __libc_lock_lock etc.), and the C++ version (if we need it) will be 
>> written as a function anyway.
> 
> OK, then how about the "arrayelts", or "array_elts"? "array_length" is a 
> bit confusion-prone, because "length" is so often one less than the 
> number of elements.

ELT is the indexing operator in Common Lisp:

   <http://www.lispworks.com/documentation/HyperSpec/Body/f_elt.htm>

To me, this name implies dereferencing some kind.  I think “length” is 
far more intuitive.  The difference between array length and string 
length is just something we have to live with, it's not going away no 
matter which name we choose.

Thanks,
Florian
  

Patch


2017-10-21  Florian Weimer  <fweimer@redhat.com>

	Add array_length and array_end macros.
	* include/array_length.h: New file.
	* stdio-common/bug16.c (do_test): Use array_length.
	* stdio-common/errlist.c (_sys_nerr): Likewise.
	* stdio-common/printf_fp.c (PRINTF_FP_FETCH): Likewise.
	* stdio-common/printf_fphex.c (__printf_fphex): Use array_end.
	* stdio-common/psiginfo.c (psiginfo): Use array_length.
	* stdio-common/test-vfprintf.c (nlocs): Remove definition.
	(do_test): Use array_length.
	* stdio-common/tst-fphex.c (do_test): Use array_end, array_length.
	* stdio-common/tst-long-dbl-fphex.c (do_test): Use array_length.
	* stdio-common/tst-printf-round.c (do_test): Likewise.
	* stdio-common/tst-swprintf.c (nbuf): Remove definition.
	(CHECK): Use array_length.
	* stdio-common/tstdiomisc.c (t3, F): Likewise.
	* stdio-common/tstscanf.c (main): Likewise.
	* stdio-common/vfprintf.c (process_string_arg): Likewise.

diff --git a/include/array_length.h b/include/array_length.h
new file mode 100644
index 0000000000..b1dca0f24b
--- /dev/null
+++ b/include/array_length.h
@@ -0,0 +1,36 @@ 
+/* The array_length macro.
+   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ARRAY_LENGTH_H
+#define _ARRAY_LENGTH_H
+
+/* 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]);                                   \
+  })
+
+/* array_end (VAR) is a pointer one past the end of the array VAR.
+   VAR must evaluate to an array, not a pointer.  */
+#define array_end(var) &(var)[array_length (var)]
+
+#endif /* _ARRAY_LENGTH_H */
diff --git a/stdio-common/bug16.c b/stdio-common/bug16.c
index 1112c39d05..91bc452826 100644
--- a/stdio-common/bug16.c
+++ b/stdio-common/bug16.c
@@ -1,3 +1,4 @@ 
+#include <array_length.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -19,7 +20,7 @@  do_test (void)
   char buf[100];
   int ret = 0;
 
-  for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+  for (size_t i = 0; i < array_length (tests); ++i)
     {
       snprintf (buf, sizeof (buf), "%.0LA", tests[i].val);
 
diff --git a/stdio-common/errlist.c b/stdio-common/errlist.c
index 0f1b72b37d..e8d0f62519 100644
--- a/stdio-common/errlist.c
+++ b/stdio-common/errlist.c
@@ -15,9 +15,9 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <stddef.h>
 
-
 const char *const _sys_errlist[] =
   {
     "Error 0",			/* 0 */
@@ -33,4 +33,4 @@  const char *const _sys_errlist[] =
     "Too many open files",	/* 10 = EMFILE */
   };
 
-const int _sys_nerr = sizeof (_sys_errlist) / sizeof (_sys_errlist[0]);
+const int _sys_nerr = array_length (_sys_errlist);
diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c
index 994497cd22..52ba46bd08 100644
--- a/stdio-common/printf_fp.c
+++ b/stdio-common/printf_fp.c
@@ -21,6 +21,7 @@ 
 /* The gmp headers need some configuration frobs.  */
 #define HAVE_ALLOCA 1
 
+#include <array_length.h>
 #include <libioP.h>
 #include <alloca.h>
 #include <ctype.h>
@@ -371,8 +372,7 @@  __printf_fp_l (FILE *fp, locale_t loc,
     else								\
       {									\
 	p.fracsize = __mpn_extract_##SUFFIX				\
-		     (fp_input,						\
-		      (sizeof (fp_input) / sizeof (fp_input[0])),	\
+		     (fp_input, array_length (fp_input),		\
 		      &p.exponent, &is_neg, VAR);			\
 	to_shift = 1 + p.fracsize * BITS_PER_MP_LIMB - MANT_DIG;	\
       }									\
diff --git a/stdio-common/printf_fphex.c b/stdio-common/printf_fphex.c
index 004d2aa716..938b0b32e0 100644
--- a/stdio-common/printf_fphex.c
+++ b/stdio-common/printf_fphex.c
@@ -17,6 +17,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <ctype.h>
 #include <ieee754.h>
 #include <math.h>
@@ -320,8 +321,8 @@  __printf_fphex (FILE *fp,
   /* Look for trailing zeroes.  */
   if (! zero_mantissa)
     {
-      wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]];
-      numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
+      wnumend = array_end (wnumbuf);
+      numend = array_end (numbuf);
       while (wnumend[-1] == L'0')
 	{
 	  --wnumend;
diff --git a/stdio-common/psiginfo.c b/stdio-common/psiginfo.c
index 7bf2e2d13f..b9c455b8f5 100644
--- a/stdio-common/psiginfo.c
+++ b/stdio-common/psiginfo.c
@@ -15,6 +15,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <errno.h>
 #include <libintl.h>
 #include <signal.h>
@@ -116,7 +117,7 @@  psiginfo (const siginfo_t *pinfo, const char *s)
 	case sig:							      \
 	  base = C(codestrs_, sig).str;					      \
 	  offarr = C (codes_, sig);					      \
-	  offarr_len = sizeof (C (codes_, sig)) / sizeof (C (codes_, sig)[0]);\
+	  offarr_len = array_length (C (codes_, sig));			      \
 	  break
 
 	  H (SIGILL);
diff --git a/stdio-common/test-vfprintf.c b/stdio-common/test-vfprintf.c
index f8bb9cee58..0fcc1adc0e 100644
--- a/stdio-common/test-vfprintf.c
+++ b/stdio-common/test-vfprintf.c
@@ -17,6 +17,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <locale.h>
 #include <mcheck.h>
 #include <stdint.h>
@@ -32,8 +33,6 @@  const char *locs[] =
 {
   "C", "de_DE.ISO-8859-1", "de_DE.UTF-8", "ja_JP.EUC-JP"
 };
-#define nlocs (sizeof (locs) / sizeof (locs[0]))
-
 
 char large[50000];
 
@@ -56,7 +55,7 @@  do_test (void)
     }
   unlink (buf);
 
-  for (i = 0; i < nlocs; ++i)
+  for (i = 0; i < array_length (locs); ++i)
     {
       FILE *fp;
       struct stat st;
diff --git a/stdio-common/tst-fphex.c b/stdio-common/tst-fphex.c
index c2e8961d62..efba482537 100644
--- a/stdio-common/tst-fphex.c
+++ b/stdio-common/tst-fphex.c
@@ -1,5 +1,6 @@ 
 /* Test program for %a printf formats.  */
 
+#include <array_length.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -49,12 +50,10 @@  do_test (void)
   const struct testcase *t;
   int result = 0;
 
-  for (t = testcases;
-       t < &testcases[sizeof testcases / sizeof testcases[0]];
-       ++t)
+  for (t = testcases; t < array_end (testcases); ++t)
     {
       CHAR_T buf[1024];
-      int n = SPRINT (buf, sizeof buf / sizeof (buf[0]), t->fmt, t->value);
+      int n = SPRINT (buf, array_length (buf), t->fmt, t->value);
       if (n != STR_LEN (t->expect) || STR_CMP (buf, t->expect) != 0)
 	{
 	  PRINT (L_("" S "\tExpected \"" S "\" (%Zu)\n\tGot      \""
diff --git a/stdio-common/tst-long-dbl-fphex.c b/stdio-common/tst-long-dbl-fphex.c
index 1170c74c4c..6a402a1c89 100644
--- a/stdio-common/tst-long-dbl-fphex.c
+++ b/stdio-common/tst-long-dbl-fphex.c
@@ -16,6 +16,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <wchar.h>
 
 /* Prototype for our test function.  */
@@ -28,9 +29,9 @@  do_test (void)
   int result = 0;
   const long double x = 24.5;
   wchar_t a[16];
-  swprintf (a, sizeof a / sizeof a[0], L"%La\n", x);
+  swprintf (a, array_length (a), L"%La\n", x);
   wchar_t A[16];
-  swprintf (A, sizeof A / sizeof A[0], L"%LA\n", x);
+  swprintf (A, array_length (a), L"%LA\n", x);
 
   /* Here wprintf can return four valid variants.  We must accept all
      of them.  */
diff --git a/stdio-common/tst-printf-round.c b/stdio-common/tst-printf-round.c
index e0073f2856..a5db3b88c2 100644
--- a/stdio-common/tst-printf-round.c
+++ b/stdio-common/tst-printf-round.c
@@ -16,6 +16,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <fenv.h>
 #include <stdio.h>
 #include <string.h>
@@ -167,7 +168,7 @@  do_test (void)
   int save_round_mode __attribute__ ((unused)) = fegetround ();
   int result = 0;
 
-  for (size_t i = 0; i < sizeof (dec_tests) / sizeof (dec_tests[0]); i++)
+  for (size_t i = 0; i < array_length (dec_tests); i++)
     {
       result |= test_dec_in_one_mode (dec_tests[i].d, dec_tests[i].fmt,
 				      dec_tests[i].rn, "default rounding mode");
@@ -197,7 +198,7 @@  do_test (void)
 #endif
     }
 
-  for (size_t i = 0; i < sizeof (hex_tests) / sizeof (hex_tests[0]); i++)
+  for (size_t i = 0; i < array_length (hex_tests); i++)
     {
       result |= test_hex_in_one_mode (hex_tests[i].d, hex_tests[i].fmt,
 				      hex_tests[i].rn, "default rounding mode");
diff --git a/stdio-common/tst-sscanf.c b/stdio-common/tst-sscanf.c
index c070e14cd7..9ccd86e7b0 100644
--- a/stdio-common/tst-sscanf.c
+++ b/stdio-common/tst-sscanf.c
@@ -16,6 +16,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <locale.h>
@@ -184,7 +185,7 @@  do_test (void)
 	break;
     }
 
-  for (i = 0; i < sizeof (int_tests) / sizeof (int_tests[0]); ++i)
+  for (i = 0; i < array_length (int_tests); ++i)
     {
       long dummy;
       int ret;
@@ -198,7 +199,7 @@  do_test (void)
 	}
     }
 
-  for (i = 0; i < sizeof (double_tests) / sizeof (double_tests[0]); ++i)
+  for (i = 0; i < array_length (double_tests); ++i)
     {
       double dummy;
       int ret;
@@ -212,7 +213,7 @@  do_test (void)
 	}
     }
 
-  for (i = 0; i < sizeof (double_tests2) / sizeof (double_tests2[0]); ++i)
+  for (i = 0; i < array_length (double_tests2); ++i)
     {
       double dummy;
       int ret;
diff --git a/stdio-common/tst-swprintf.c b/stdio-common/tst-swprintf.c
index ce62c6bf68..07194eb67d 100644
--- a/stdio-common/tst-swprintf.c
+++ b/stdio-common/tst-swprintf.c
@@ -1,3 +1,4 @@ 
+#include <array_length.h>
 #include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -16,7 +17,6 @@  static int
 do_test (void)
 {
   wchar_t buf[1000];
-#define nbuf (sizeof (buf) / sizeof (buf[0]))
   int result = 0;
   ssize_t n;
 
@@ -27,7 +27,7 @@  do_test (void)
     }
 
 #define CHECK(fmt, nexp, exp) \
-  n = swprintf (buf, nbuf, fmt, input);					      \
+  n = swprintf (buf, array_length (buf), fmt, input);			      \
   if (n != nexp)							      \
     {									      \
       printf ("swprintf (.., .., L\"%ls\", \"%ls\") return %d, not %d\n",     \
diff --git a/stdio-common/tstdiomisc.c b/stdio-common/tstdiomisc.c
index 89009e0549..c2fc73deb1 100644
--- a/stdio-common/tstdiomisc.c
+++ b/stdio-common/tstdiomisc.c
@@ -1,3 +1,4 @@ 
+#include <array_length.h>
 #include <float.h>
 #include <math.h>
 #include <stdio.h>
@@ -66,8 +67,7 @@  t3 (void)
   retval = sprintf (buf, "%p", (char *) NULL);
   result |= retval != 5 || strcmp (buf, "(nil)") != 0;
 
-  retval = swprintf (wbuf, sizeof (wbuf) / sizeof (wbuf[0]),
-		     L"%p", (char *) NULL);
+  retval = swprintf (wbuf, array_length (wbuf), L"%p", (char *) NULL);
   result |= retval != 5 || wcscmp (wbuf, L"(nil)") != 0;
 
   return result;
@@ -142,38 +142,38 @@  F (void)
   printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n",
 	  buf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G",
+  swprintf (wbuf, array_length (wbuf), L"%a %A %e %E %f %F %g %G",
 	    qnanval, qnanval, qnanval, qnanval,
 	    qnanval, qnanval, qnanval, qnanval);
   result |= wcscmp (wbuf, L"nan NAN nan NAN nan NAN nan NAN") != 0;
   printf ("expected L\"nan NAN nan NAN nan NAN nan NAN\", got L\"%S\"\n", wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G",
+  swprintf (wbuf, array_length (wbuf), L"%a %A %e %E %f %F %g %G",
 	    -qnanval, -qnanval, -qnanval, -qnanval,
 	    -qnanval, -qnanval, -qnanval, -qnanval);
   result |= wcscmp (wbuf, L"-nan -NAN -nan -NAN -nan -NAN -nan -NAN") != 0;
   printf ("expected L\"-nan -NAN -nan -NAN -nan -NAN -nan -NAN\", got L\"%S\"\n",
 	  wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G",
+  swprintf (wbuf, array_length (wbuf), L"%a %A %e %E %f %F %g %G",
 	    snanval, snanval, snanval, snanval,
 	    snanval, snanval, snanval, snanval);
   result |= wcscmp (wbuf, L"nan NAN nan NAN nan NAN nan NAN") != 0;
   printf ("expected L\"nan NAN nan NAN nan NAN nan NAN\", got L\"%S\"\n", wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G",
+  swprintf (wbuf, array_length (wbuf), L"%a %A %e %E %f %F %g %G",
 	    msnanval, msnanval, msnanval, msnanval,
 	    msnanval, msnanval, msnanval, msnanval);
   result |= wcscmp (wbuf, L"-nan -NAN -nan -NAN -nan -NAN -nan -NAN") != 0;
   printf ("expected L\"-nan -NAN -nan -NAN -nan -NAN -nan -NAN\", got L\"%S\"\n",
 	  wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G",
+  swprintf (wbuf, array_length (wbuf), L"%a %A %e %E %f %F %g %G",
 	    infval, infval, infval, infval, infval, infval, infval, infval);
   result |= wcscmp (wbuf, L"inf INF inf INF inf INF inf INF") != 0;
   printf ("expected L\"inf INF inf INF inf INF inf INF\", got L\"%S\"\n", wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G",
+  swprintf (wbuf, array_length (wbuf), L"%a %A %e %E %f %F %g %G",
 	    -infval, -infval, -infval, -infval,
 	    -infval, -infval, -infval, -infval);
   result |= wcscmp (wbuf, L"-inf -INF -inf -INF -inf -INF -inf -INF") != 0;
@@ -223,14 +223,14 @@  F (void)
   printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n",
 	  buf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]),
+  swprintf (wbuf, array_length (wbuf),
 	    L"%La %LA %Le %LE %Lf %LF %Lg %LG",
 	    lqnanval, lqnanval, lqnanval, lqnanval,
 	    lqnanval, lqnanval, lqnanval, lqnanval);
   result |= wcscmp (wbuf, L"nan NAN nan NAN nan NAN nan NAN") != 0;
   printf ("expected L\"nan NAN nan NAN nan NAN nan NAN\", got L\"%S\"\n", wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]),
+  swprintf (wbuf, array_length (wbuf),
 	    L"%La %LA %Le %LE %Lf %LF %Lg %LG",
 	    -lqnanval, -lqnanval, -lqnanval, -lqnanval,
 	    -lqnanval, -lqnanval, -lqnanval, -lqnanval);
@@ -238,14 +238,14 @@  F (void)
   printf ("expected L\"-nan -NAN -nan -NAN -nan -NAN -nan -NAN\", got L\"%S\"\n",
 	  wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]),
+  swprintf (wbuf, array_length (wbuf),
 	    L"%La %LA %Le %LE %Lf %LF %Lg %LG",
 	    lsnanval, lsnanval, lsnanval, lsnanval,
 	    lsnanval, lsnanval, lsnanval, lsnanval);
   result |= wcscmp (wbuf, L"nan NAN nan NAN nan NAN nan NAN") != 0;
   printf ("expected L\"nan NAN nan NAN nan NAN nan NAN\", got L\"%S\"\n", wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]),
+  swprintf (wbuf, array_length (wbuf),
 	    L"%La %LA %Le %LE %Lf %LF %Lg %LG",
 	    lmsnanval, lmsnanval, lmsnanval, lmsnanval,
 	    lmsnanval, lmsnanval, lmsnanval, lmsnanval);
@@ -253,14 +253,14 @@  F (void)
   printf ("expected L\"-nan -NAN -nan -NAN -nan -NAN -nan -NAN\", got L\"%S\"\n",
 	  wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]),
+  swprintf (wbuf, array_length (wbuf),
 	    L"%La %LA %Le %LE %Lf %LF %Lg %LG",
 	    linfval, linfval, linfval, linfval,
 	    linfval, linfval, linfval, linfval);
   result |= wcscmp (wbuf, L"inf INF inf INF inf INF inf INF") != 0;
   printf ("expected L\"inf INF inf INF inf INF inf INF\", got L\"%S\"\n", wbuf);
 
-  swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]),
+  swprintf (wbuf, array_length (wbuf),
 	    L"%La %LA %Le %LE %Lf %LF %Lg %LG",
 	    -linfval, -linfval, -linfval, -linfval,
 	    -linfval, -linfval, -linfval, -linfval);
diff --git a/stdio-common/tstscanf.c b/stdio-common/tstscanf.c
index 50d0f33acf..d2ef4e8dee 100644
--- a/stdio-common/tstscanf.c
+++ b/stdio-common/tstscanf.c
@@ -15,6 +15,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #ifdef	BSD
 #include </usr/include/stdio.h>
 #else
@@ -154,7 +155,7 @@  main (int argc, char **argv)
       {
 	int count;
 
-	if (rounds++ >= sizeof (ok) / sizeof (ok[0]))
+	if (rounds++ >= array_length (ok))
 	  {
 	    fputs ("test failed!\n", stdout);
 	    result = 1;
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 23d2679f39..e272237307 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -15,6 +15,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <ctype.h>
 #include <limits.h>
 #include <printf.h>
@@ -995,11 +996,10 @@  static const uint8_t jump_table[] =
 	if (string == NULL)						      \
 	  {								      \
 	    /* Write "(null)" if there's space.  */			      \
-	    if (prec == -1						      \
-		|| prec >= (int) (sizeof (null) / sizeof (null[0])) - 1)      \
+	    if (prec == -1 || prec >= (int) array_length (null) - 1)          \
 	      {								      \
 		string = (CHAR_T *) null;				      \
-		len = (sizeof (null) / sizeof (null[0])) - 1;		      \
+		len = array_length (null) - 1;				      \
 	      }								      \
 	    else							      \
 	      {								      \