...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stddef.h> #include <assert.h> #include <limits.h> #include <inttypes.h> extern size_t popcount(uintmax_t); #define UWIDTHPRECISION(umax_value) popcount(umax_value) void func(signed int si_a, signed int si_b) { signed int result; signed long long tmp; assert(UWIDTHPRECISION(ULLONG_MAX) >= 2 * UWIDTHPRECISION(UINT_MAX)); tmp = (signed long long)si_a * (signed long long)si_b; /* * If the product cannot be represented as a 32-bit integer, * handle as an error condition. */ if ((tmp > INT_MAX) || (tmp < INT_MIN)) { /* Handle error */ } else { result = (int)tmp; } /* ... */ } |
The assertion fails if long long
has less than twice the width of int
. The UWIDTHPRECISION()
macro and popcount()
function are explained in INT35-C. Use correct integer precisions. The following portable compliant solution can be used for on any conforming implementation, including those where this assertion fails:
...
The C Standard, 6.5.7 paragraph 4 [ISO/IEC 9899:2011], states
...
In almost every case, an attempt to shift by a negative number of bits or by more bits than exist in the operand indicates a bug (logic error). These issues are covered by INT34-C. Do not shift a negative number of bits or more bits than exist in the operand.
Noncompliant Code Example
This noncompliant code example can result in an unrepresentable value.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <limits.h> #include <stddef.h> #include <inttypes.h> extern size_t popcount(uintmax_t); #define UWIDTHPRECISION(umax_value) popcount(umax_value) void func(signed long si_a, signed long si_b) { signed long result; if ((si_a < 0) || (si_b < 0) || (si_b >= UWIDTHPRECISION(ULONG_MAX)) { /* Handle error */ } else { result = si_a << si_b; } /* ... */ } |
Compliant Solution
This compliant solution eliminates the possibility of overflow resulting from a left-shift operation:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <limits.h> #include <stddef.h> #include <inttypes.h> extern size_t popcount(uintmax_t); #define UWIDTHPRECISION(umax_value) popcount(umax_value) void func(signed long si_a, signed long si_b) { signed long result; if ((si_a < 0) || (si_b < 0) || (si_b >= UWIDTHPRECISION(ULONG_MAX)) || (si_a > (LONG_MAX >> si_b))) { /* Handle error */ } else { result = si_a << si_b; } /* ... */ } |
The UWIDTHThe PRECISION()
macro provides the correct width for an unsigned integer type (see INT19INT35-C. Correctly compute Use correct integer widthsprecisions).
Anchor | ||||
---|---|---|---|---|
|
...