1

So I have a task to check for overflow when adding two int32_t numbers. In case of overflow my function must return maximum or minimum number of int32_t, depending on the sign of overflow, but using constants like UINT32_MAX is restricted. How do I do that? Here's the code if it will help you:

#include "inttypes.h"

int32_t
satsum(int32_t v1, int32_t v2) {
    int32_t res = 0;
    if(__builtin_sadd_overflow(v1, v2, &res)) {
        if (res < 0) {
            return ?
        }
        return ?
    } else {
        res = v1 + v2;
        return res;
    }
}
Demo_13B
  • 45
  • 1
  • 3
  • Please [edit] your question to include the full assignment or exercise text, including notes about restrictions (like the one about macro usage). – Some programmer dude Nov 13 '20 at 13:12
  • *but using constants like UINT32_MAX is restricted* Restricted?!? By **who**? Values such as `INT32_MAX` are **required** by the C standard to be defined. In fact, without them it's probably impossible to determine the maximum value for something like `int32_t` because signed integer overflow is undefined behavior. **Use the standard C definition of `INT32_MAX` and tell the incompetent source of your restriction to sod off because you need to write code that doesn't invoke undefined behavior.** – Andrew Henle Nov 13 '20 at 13:29
  • 1
    And if someone is saying things like, "You can't use `INT32_MAX` in your code", I'd sure as heck question their competence in everything else they do. – Andrew Henle Nov 13 '20 at 13:31

2 Answers2

1

The value of INT32_MAX (maximum value of int32_t) and INT32_MIN (minimum value of int32_t) are defined in C specification, so you can write the values instead of using the constants.

Quote from N1570 7.20.2.1 Limits of exact-width integer types:

— minimum values of exact-width signed integer types
INTN_MIN exactly −(2N-1)
— maximum values of exact-width signed integer types
INTN_MAX exactly 2N−1 − 1
— maximum values of exact-width unsigned integer types
UINTN_MAX exactly 2N − 1

Here is one point: 2N can be represented as 1<<N, but 1<<31 will cause overflow, so you should use ((1<<30)-1)*2+1 instead of 1<<31.

Also you should use INT32_C macor to use literals of int32_t instead of int.

In conclusion, what you should use are:

  • The maximum value of int32_t: ((INT32_C(1)<<30)-1)*2+1
  • The minimum value of int32_t: -((INT32_C(1)<<30)-1)*2-2
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
-1

int32_t is guaranteed to be in 2's complement form. This means that the maximum value is guaranteed to be 2^31 -1 and the minimum value is guaranteed to be -2^31.

So you can simply do this:

const int32_t i32_min = 1u << 31;
const int32_t i32_max = (1u << 31)-1u;

This code will cause implementation-defined conversions from unsigned to signed, which in this case means the conversion will have a 2's complement format.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • The implementation-defined conversion is implementation-defined. It is not constrained to reinterpret the bits as two’s complement or (equivalently) to wrap modulo 2^32. The implementation may define the conversion to clamp, to trap, or to return other values. Additionally, `1u << 31` may have undefined behavior. – Eric Postpischil Nov 13 '20 at 14:41
  • @EricPostpischil Then kindly explain how a 2's complement number can have trap representations. This works just fine on real-world computers. If ported to non-existing fictional computers, I suppose it may break. Unsigned shifts cannot overflow as per 6.5.7/4 "If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in the result type." – Lundin Nov 13 '20 at 14:48
  • (a) I should have written that it could signal, not trap. The conversion from `unsigned int` to `int32_t` may signal because C 2018 6.3.1.3 3 says “either the result is implementation-defined or an implementation-defined signal is raised.” (b) Choosing whether to produce the result as if wrapped/reinterpreted or to produce a clamped or other result or to signal is a function of the C implementation, not the computer. (c) You are correct unsigned shift will not overflow. That means the behavior will not be undefined. However, it will be wrong; `int32_min = 1u << 31` will set `int32_min` to 0. – Eric Postpischil Nov 13 '20 at 14:57