From 09b59d2814db9d80fe61cc4259a83e9b68078e35 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Thu, 6 Sep 2018 14:28:38 +0200 Subject: [PATCH] limits-h: Provide numerical limits macros. * lib/limits.in.h (LLONG_MIN, LLONG_MAX, ULLONG_MAX): Define also for IRIX and for GCC. (WORD_BIT, LONG_BIT): Define. * m4/limits-h.m4 (gl_LIMITS_H): Set LIMITS_H to non-empty also when does not define LLONG_MAX or WORD_BIT. * tests/test-limits-h.c (TYPE_SIGNED, TYPE_WIDTH, TYPE_MINIMUM, TYPE_MAXIMUM): New macros, from intprops.h. Add tests for CHAR_BIT, WORD_BIT, LONG_BIT, _MIN, and _MAX. * doc/posix-headers/limits.texi: Document what the 'limits-h' module provides. --- ChangeLog | 14 +++++++ doc/posix-headers/limits.texi | 28 ++++++++------ lib/limits.in.h | 44 ++++++++++++++++++---- m4/limits-h.m4 | 16 +++++--- tests/test-limits-h.c | 71 ++++++++++++++++++++++++++++++++++- 5 files changed, 146 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8b342636e9..2dfbd27c74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2018-09-06 Bruno Haible + + limits-h: Provide numerical limits macros. + * lib/limits.in.h (LLONG_MIN, LLONG_MAX, ULLONG_MAX): Define also for + IRIX and for GCC. + (WORD_BIT, LONG_BIT): Define. + * m4/limits-h.m4 (gl_LIMITS_H): Set LIMITS_H to non-empty also when + does not define LLONG_MAX or WORD_BIT. + * tests/test-limits-h.c (TYPE_SIGNED, TYPE_WIDTH, TYPE_MINIMUM, + TYPE_MAXIMUM): New macros, from intprops.h. + Add tests for CHAR_BIT, WORD_BIT, LONG_BIT, _MIN, and _MAX. + * doc/posix-headers/limits.texi: Document what the 'limits-h' module + provides. + 2018-09-05 Bruno Haible fcntl: Don't access nonexistent optional argument. diff --git a/doc/posix-headers/limits.texi b/doc/posix-headers/limits.texi index be1220eefe..2cf51ac502 100644 --- a/doc/posix-headers/limits.texi +++ b/doc/posix-headers/limits.texi @@ -3,28 +3,32 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html} -Gnulib module: gethostname +Gnulib module: limits-h or gethostname -Portability problems fixed by Gnulib: +Portability problems fixed by Gnulib module @code{limits-h}: @itemize @item -The @code{HOST_NAME_MAX} macro is not defined on some platforms: -Mac OS X 10.5, FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, -IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin 1.5.x, mingw, MSVC 14, Interix 3.5, BeOS. +The macros @code{LLONG_MIN}, @code{LLONG_MAX}, @code{ULLONG_MAX} are not +defined on some platforms: +older glibc systems (e.g. Fedora 1), AIX 5.1, HP-UX 11, IRIX 6.5, OpenVMS, OSF/1 5.1 with gcc. +@item +The macros @code{WORD_BIT}, @code{LONG_BIT} are not defined on some platforms: +glibc 2.11 without @code{-D_GNU_SOURCE}, Cygwin, mingw, MSVC 14. @item Macros like @code{CHAR_WIDTH} are not defined on some platforms: glibc 2.24, many others. @end itemize -Portability problems not fixed by Gnulib: +Portability problems fixed by Gnulib module @code{gethostname}: @itemize @item -The macros @code{LLONG_MIN}, @code{LLONG_MAX}, @code{ULLONG_MAX} are not -defined on some platforms: -AIX 5.1, HP-UX 11, IRIX 6.5, OpenVMS, OSF/1 5.1 with gcc. -@item -The macros @code{WORD_BIT}, @code{LONG_BIT} are not defined on some platforms: -glibc 2.11 without @code{-D_GNU_SOURCE}, Cygwin, mingw, MSVC 14. +The @code{HOST_NAME_MAX} macro is not defined on some platforms: +Mac OS X 10.5, FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, +IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin 1.5.x, mingw, MSVC 14, Interix 3.5, BeOS. +@end itemize + +Portability problems not fixed by Gnulib: +@itemize @item The macro @code{SSIZE_MAX} has the wrong type, albeit with the correct value: diff --git a/lib/limits.in.h b/lib/limits.in.h index c3915dce18..5b4c3eed77 100644 --- a/lib/limits.in.h +++ b/lib/limits.in.h @@ -28,15 +28,32 @@ #ifndef _@GUARD_PREFIX@_LIMITS_H #define _@GUARD_PREFIX@_LIMITS_H -/* For HP-UX 11.31. */ -#if defined LONG_LONG_MIN && !defined LLONG_MIN -# define LLONG_MIN LONG_LONG_MIN +#ifndef LLONG_MIN +# if defined LONG_LONG_MIN /* HP-UX 11.31 */ +# define LLONG_MIN LONG_LONG_MIN +# elif defined LONGLONG_MIN /* IRIX 6.5 */ +# define LLONG_MIN LONGLONG_MIN +# elif defined __GNUC__ +# define LLONG_MIN (- __LONG_LONG_MAX__ - 1LL) +# endif #endif -#if defined LONG_LONG_MAX && !defined LLONG_MAX -# define LLONG_MAX LONG_LONG_MAX +#ifndef LLONG_MAX +# if defined LONG_LONG_MAX /* HP-UX 11.31 */ +# define LLONG_MAX LONG_LONG_MAX +# elif defined LONGLONG_MAX /* IRIX 6.5 */ +# define LLONG_MAX LONGLONG_MAX +# elif defined __GNUC__ +# define LLONG_MAX __LONG_LONG_MAX__ +# endif #endif -#if defined ULONG_LONG_MAX && !defined ULLONG_MAX -# define ULLONG_MAX ULONG_LONG_MAX +#ifndef ULLONG_MAX +# if defined ULONG_LONG_MAX /* HP-UX 11.31 */ +# define ULLONG_MAX ULONG_LONG_MAX +# elif defined ULONGLONG_MAX /* IRIX 6.5 */ +# define ULLONG_MAX ULONGLONG_MAX +# elif defined __GNUC__ +# define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1ULL) +# endif #endif /* The number of usable bits in an unsigned or signed integer type @@ -53,6 +70,19 @@ #define _GL_COB8(n) (_GL_COB4 ((n) >> 4) + _GL_COB4 (n)) #define _GL_COB4(n) (!!((n) & 8) + !!((n) & 4) + !!((n) & 2) + !!((n) & 1)) +#ifndef WORD_BIT +/* Assume 'int' is 32 bits wide. */ +# define WORD_BIT 32 +#endif +#ifndef LONG_BIT +/* Assume 'long' is 32 or 64 bits wide. */ +# if LONG_MAX == INT_MAX +# define LONG_BIT 32 +# else +# define LONG_BIT 64 +# endif +#endif + /* Macros specified by ISO/IEC TS 18661-1:2014. */ #if (! defined ULLONG_WIDTH \ diff --git a/m4/limits-h.m4 b/m4/limits-h.m4 index 8388663439..3a2cd91ead 100644 --- a/m4/limits-h.m4 +++ b/m4/limits-h.m4 @@ -11,14 +11,18 @@ AC_DEFUN_ONCE([gl_LIMITS_H], [ gl_CHECK_NEXT_HEADERS([limits.h]) - AC_CACHE_CHECK([whether limits.h has ULLONG_WIDTH etc.], + AC_CACHE_CHECK([whether limits.h has LLONG_MAX, WORD_BIT, ULLONG_WIDTH etc.], [gl_cv_header_limits_width], [AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([[#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ - #define __STDC_WANT_IEC_60559_BFP_EXT__ 1 - #endif - #include - int ullw = ULLONG_WIDTH;]])], + [AC_LANG_PROGRAM( + [[#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ + #define __STDC_WANT_IEC_60559_BFP_EXT__ 1 + #endif + #include + long long llm = LLONG_MAX; + int wb = WORD_BIT; + int ullw = ULLONG_WIDTH; + ]])], [gl_cv_header_limits_width=yes], [gl_cv_header_limits_width=no])]) if test "$gl_cv_header_limits_width" = yes; then diff --git a/tests/test-limits-h.c b/tests/test-limits-h.c index 29b5127391..ee30bdef46 100644 --- a/tests/test-limits-h.c +++ b/tests/test-limits-h.c @@ -26,11 +26,78 @@ # pragma GCC diagnostic ignored "-Woverlength-strings" #endif -/* Macros specified by ISO/IEC TS 18661-1:2014. */ - #define verify_width(width, min, max) \ verify ((max) >> ((width) - 1 - ((min) < 0)) == 1) +/* Macros borrowed from intprops.h. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) +#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) +#define TYPE_MAXIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) -1 \ + : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) + +/* Type width macros. */ + +int type_bits[] = + { + CHAR_BIT, + WORD_BIT, + LONG_BIT + }; +verify_width (CHAR_BIT, CHAR_MIN, CHAR_MAX); +verify_width (WORD_BIT, INT_MIN, INT_MAX); +verify_width (LONG_BIT, LONG_MIN, LONG_MAX); + +/* Numerical limit macros. */ + +char limits1[] = { CHAR_MIN, CHAR_MAX }; +verify (TYPE_MINIMUM (char) == CHAR_MIN); +verify (TYPE_MAXIMUM (char) == CHAR_MAX); + +signed char limits2[] = { SCHAR_MIN, SCHAR_MAX }; +verify (TYPE_MINIMUM (signed char) == SCHAR_MIN); +verify (TYPE_MAXIMUM (signed char) == SCHAR_MAX); + +unsigned char limits3[] = { UCHAR_MAX }; +verify (TYPE_MINIMUM (unsigned char) == 0); +verify (TYPE_MAXIMUM (unsigned char) == UCHAR_MAX); + +short limits4[] = { SHRT_MIN, SHRT_MAX }; +verify (TYPE_MINIMUM (short int) == SHRT_MIN); +verify (TYPE_MAXIMUM (short int) == SHRT_MAX); + +unsigned short limits5[] = { USHRT_MAX }; +verify (TYPE_MINIMUM (unsigned short int) == 0); +verify (TYPE_MAXIMUM (unsigned short int) == USHRT_MAX); + +int limits6[] = { INT_MIN, INT_MAX }; +verify (TYPE_MINIMUM (int) == INT_MIN); +verify (TYPE_MAXIMUM (int) == INT_MAX); + +unsigned int limits7[] = { UINT_MAX }; +verify (TYPE_MINIMUM (unsigned int) == 0); +verify (TYPE_MAXIMUM (unsigned int) == UINT_MAX); + +long limits8[] = { LONG_MIN, LONG_MAX }; +verify (TYPE_MINIMUM (long int) == LONG_MIN); +verify (TYPE_MAXIMUM (long int) == LONG_MAX); + +unsigned long limits9[] = { ULONG_MAX }; +verify (TYPE_MINIMUM (unsigned long int) == 0); +verify (TYPE_MAXIMUM (unsigned long int) == ULONG_MAX); + +long long limits10[] = { LLONG_MIN, LLONG_MAX }; +verify (TYPE_MINIMUM (long long int) == LLONG_MIN); +verify (TYPE_MAXIMUM (long long int) == LLONG_MAX); + +unsigned long long limits11[] = { ULLONG_MAX }; +verify (TYPE_MINIMUM (unsigned long long int) == 0); +verify (TYPE_MAXIMUM (unsigned long long int) == ULLONG_MAX); + +/* Macros specified by ISO/IEC TS 18661-1:2014. */ + verify_width (CHAR_WIDTH, CHAR_MIN, CHAR_MAX); verify_width (SCHAR_WIDTH, SCHAR_MIN, SCHAR_MAX); verify_width (UCHAR_WIDTH, 0, UCHAR_MAX); -- 2.39.5