As written yesterday, the use of __SIZE_TYPE__ is wrong. And the "simplification" of sizeof ((a)[0]) to sizeof *(a) is besides the point, because countof is about array elements and the common syntax for accessing elements is array[index].
I'm therefore applying this patch: 2025-06-03 Bruno Haible <br...@clisp.org> stdcountof-h: Always return size_t, in a better way. * lib/stdcountof.in.h: Revert last change. Include <stddef.h> unconditionally. (countof): Cast value to size_t. * tests/test-stdcountof-h.c (HAVE___TYPEOF__, HAVE__GENERIC): New macros. (test_func): Check the return type of countof. diff --git a/lib/stdcountof.in.h b/lib/stdcountof.in.h index 6803b676bc..105cf209a5 100644 --- a/lib/stdcountof.in.h +++ b/lib/stdcountof.in.h @@ -18,10 +18,8 @@ #ifndef _GL_STDCOUNTOF_H #define _GL_STDCOUNTOF_H -#ifndef __SIZE_TYPE__ -# include <stddef.h> -# define __SIZE_TYPE__ size_t -#endif +/* Get size_t. */ +#include <stddef.h> /* Returns the number of elements of the array A, as a value of type size_t. Example declarations of arrays: @@ -33,7 +31,7 @@ void func (int a[10]) { ... } */ #define countof(a) \ - ((__SIZE_TYPE__) (sizeof (a) / sizeof *(a) + 0 * _gl_verify_is_array (a))) + ((size_t) (sizeof (a) / sizeof ((a)[0]) + 0 * _gl_verify_is_array (a))) /* Attempts to verify that A is an array. */ #if defined __cplusplus @@ -55,7 +53,7 @@ template <typename T> template <typename T> struct _gl_array_type_test<T[]> { static const int is_array = 1; }; /* Bounded arrays. */ -template <typename T, __SIZE_TYPE__ N> +template <typename T, size_t N> struct _gl_array_type_test<T[N]> { static const int is_array = 1; }; # define _gl_verify_is_array(a) \ sizeof (_gl_verify_type<_gl_array_type_test<decltype(a)>::is_array>) @@ -69,7 +67,7 @@ template <typename T> template <typename T> struct _gl_array_type_test<T[]> { char small; }; /* Bounded arrays. */ -template <typename T, __SIZE_TYPE__ N> +template <typename T, size_t N> struct _gl_array_type_test<T[N]> { char small; }; /* The T& parameter is essential here: it prevents decay (array-to-pointer conversion). */ diff --git a/tests/test-stdcountof-h.c b/tests/test-stdcountof-h.c index 619a666186..a382dc1b1e 100644 --- a/tests/test-stdcountof-h.c +++ b/tests/test-stdcountof-h.c @@ -20,6 +20,25 @@ #include "macros.h" +/* Whether the compiler supports __typeof__. */ +#if ((defined __GNUC__ && 2 <= __GNUC__) \ + || (defined __clang_major__ && 4 <= __clang_major__) \ + || (defined __IBMC__ && 1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ + || (defined __SUNPRO_C && 0x5110 <= __SUNPRO_C && !__STDC__) \ + || (defined _MSC_VER && 1939 <= _MSC_VER)) +# define HAVE___TYPEOF__ 1 +#endif + +/* Whether the compiler supports _Generic. + Test program: + int f (int x) { return _Generic (x, char *: 2, int: 3); } + */ +#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \ + || (defined __clang__ && __clang_major__ >= 3) \ + || (defined __SUNPRO_C && __SUNPRO_C >= 0x5150) +# define HAVE__GENERIC 1 +#endif + extern int integer; extern int unbounded[]; extern int bounded[10]; @@ -47,6 +66,13 @@ test_func (int parameter[3]) ASSERT (countof (integer) >= 0); ASSERT (countof (unbounded) >= 0); #endif + + /* Check that countof(...) is an expression of type size_t. */ +#if !defined __cplusplus && HAVE___TYPEOF__ && HAVE__GENERIC + ASSERT (_Generic (__typeof__ (countof (bounded)), size_t: 1, default: 0)); + ASSERT (_Generic (__typeof__ (countof (multidimensional)), size_t: 1, default: 0)); + ASSERT (_Generic (__typeof__ (countof (local_bounded)), size_t: 1, default: 0)); +#endif } int