]> Savannah Git Hosting - gnulib.git/commitdiff
intprops: new macro INT_PROMOTE
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 7 Feb 2025 22:36:55 +0000 (14:36 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 7 Feb 2025 22:37:35 +0000 (14:37 -0800)
Something like this was requested for Emacs.
* doc/intprops.texi (Arithmetic Type Conversion): New section.
* lib/intprops.h (INT_PROMOTE): New macro.
* tests/test-intprops.c: Test it.

ChangeLog
doc/intprops.texi
lib/intprops.h
tests/test-intprops.c

index 610560efa31993cb64e1994829878385df1f9b0a..a08e7a022005e6552525c885c29bc61ffa192aa9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2025-02-07  Paul Eggert  <eggert@cs.ucla.edu>
+
+       intprops: new macro INT_PROMOTE
+       Something like this was requested for Emacs.
+       * doc/intprops.texi (Arithmetic Type Conversion): New section.
+       * lib/intprops.h (INT_PROMOTE): New macro.
+       * tests/test-intprops.c: Test it.
+
 2025-02-05  Paul Eggert  <eggert@cs.ucla.edu>
 
        errno-h: document Haiku errors can’t be -1
index bdb96c295d755c4cdd1a738d7717440fadff3efa..1251f3d3c5efdf0238ea4679cc531058f4f93ecf 100644 (file)
@@ -49,6 +49,7 @@ but it does not assume that signed integer arithmetic wraps around.
 
 @menu
 * Arithmetic Type Properties::  Determining properties of arithmetic types.
+* Arithmetic Type Conversion::  Converting arithmetic types.
 * Integer Bounds::              Bounds on integer values and representations.
 * Checking Integer Overflow::   Checking for overflow while computing integers.
 * Wraparound Arithmetic::       Well-defined behavior on integer overflow.
@@ -99,6 +100,62 @@ CLOCKS_PER_SEC_is_signed (void)
 @}
 @end example
 
+@node Arithmetic Type Conversion
+@subsection Arithmetic Type Conversion
+
+@cindex type conversion, arithmetic
+@cindex arithmetic type conversion
+@cindex integer type conversion
+
+Here are some ways in C to convert an arithmetic expression @var{e} to
+a possibly different arithmetic type @var{t}.
+
+@itemize @bullet
+@item
+An explicit conversion like @code{((@var{t}) @var{e})} is powerful and
+can therefore be dangerous, because the conversion can succeed even if
+neither @var{e} nor @var{t} happens to have an arithmetic type.  For
+example, if @var{e} is a pointer, @code{((long int) @var{e})} will do
+a conversion even if that was not the intent.
+
+@item
+An implicit conversion like @code{@var{t} v = @var{e};} is less
+powerful, as it does not convert from pointers.  However, it can lose
+information and sign, as in for example @code{int v = -0.9;} which
+sets @code{v} to zero.
+
+@item
+A no-op arithmetic expression like @code{+@var{e}} is even less
+powerful, as it preserves value (including sign) because it does only
+integer promotions.  That is, it converts to @code{int} if that can
+represent all values of @code{e}'s underlying type, otherwise to
+@code{unsigned int} if that can represent all values, and
+otherwise it does no conversion.
+@end itemize
+
+@findex INT_PROMOTE
+@code{INT_PROMOTE (@var{e})} is an expression with the same value as
+the arithmetic expression @var{e} but with @var{e}'s type after
+any integer promotion.  It behaves like @code{+@var{e}}.
+
+In the following example, using @code{INT_PROMOTE} pacifies GCC's
+@code{-Wswitch-enum} option, and may help human readers see what is
+going on even if they are not expert in C's integer promotion rules
+and might be confused by the simpler @code{switch (+v)}.
+
+@example
+enum @{ A = 1, B, C, D, E @} v = ...;
+switch (INT_PROMOTE (v))
+  @{
+    case A: case C:
+      return true;
+    default:
+      /* Handle all other cases,
+         even cases like v == 0.  */
+      return false;
+  @}
+@end example
+
 @node Integer Bounds
 @subsection Integer Bounds
 
index 92dfef2500ac1387caaafbd8d1ffcfc05a2d0440..83efe39910aaf1025a37c362a391b0156f718455 100644 (file)
    signed or floating type.  Do not evaluate E.  */
 #define EXPR_SIGNED(e) _GL_EXPR_SIGNED (e)
 
+/* The same value as as the arithmetic expression E, but with E's type
+   after integer promotions.  For example, if E is of type 'enum {A, B}'
+   then 'switch (INT_PROMOTE (E))' pacifies gcc -Wswitch-enum if some
+   enum values are deliberately omitted from the switch's cases.
+   Here, unary + is safer than a cast or inline function, as unary +
+   does only integer promotions.  */
+#define INT_PROMOTE(e) (+ (e))
+
 
 /* Minimum and maximum values for integer types and expressions.  */
 
index e3f165f146c9f7c4c9430cc865cd8f59cb075d14..026c615abaf5bcdb128cffb2005453f03b53b6dc 100644 (file)
 
 #define DONTCARE __LINE__
 
+/* Check that INT_PROMOTE promotes to int.
+   GCC < 4.9 lacks _Generic even though it may claim C11 conformance.  */
+#if (201112 <= __STDC_VERSION__ \
+     && (!defined __GNUC__ || 4 < __GNUC__ + (9 <= __GNUC_MINOR__) \
+         || defined __clang__))
+int check_INT_PROMOTE = _Generic (INT_PROMOTE ((short int) 0), int: 0);
+#endif
+
 int int_minus_2 = -2;
 int int_1 = 1;