9

I have some code in a function which will change/update values with the increment/decrement operator. For example:

static void update_value(char op)
{
    if (op == '+')
        value++;    // uint32_t global value
    else
        value--;
}

The function does not check whether we've gone over/under max/min values. So the caller can call it 20 times when value is say 16. resulting in 2^32 - 1 - 4.

I'd like to guard against that but I would like to use standard library constants. I remember there was a size_t (or similar) variable that would represent the largest number that a uint32_t can hold.

I can't remember the exact constants nor the header where they were defined. Any help?

s5s
  • 11,159
  • 21
  • 74
  • 121
  • 9
    C or C++ answers will be different – Denis Ermolin Nov 30 '12 at 14:09
  • "the largest number that a uint32_t can hold" - `~(uint32_t)0` – chill Nov 30 '12 at 14:11
  • @chill: This works only for some systems. The portable solution is using the limits defined in the limits includes. – datenwolf Nov 30 '12 at 14:15
  • A portable value is also `-1`, but using the macro (or the C++ trait) is more readable, since it makes your *intention* obvious. – Kerrek SB Nov 30 '12 at 14:19
  • 2
    The maximum value that uint32_t can hold is always 4,29 billion (2^32), or more easily written: 0xFFFFFFFF. Simply hardcode it, 32 bits will always be 32 bits. – Lundin Nov 30 '12 at 14:27
  • ...although using the UINT32_MAX constant in stdint.h is more elegant. – Lundin Nov 30 '12 at 14:31
  • @datenwolf, what are the systems where it won't work? – chill Nov 30 '12 at 14:37
  • 2
    In fact the C99 standard explicitly says "If the promoted type is an unsigned type, the expression `~E` is equivalent to the maximum value representable in that type minus `E`. [6.5.3.3 Unary arithmetic operators #4]" – chill Nov 30 '12 at 14:43
  • My bad I was thinking about signed types (in the case of signed type you've to consider 1-complement vs. 2-complement), not unsigned. – datenwolf Nov 30 '12 at 14:46
  • BTW you should also protect against underflow. See http://stackoverflow.com/questions/2760502/question-about-c-behaviour-for-unsigned-integer-underflow – Peter M Nov 30 '12 at 15:21

7 Answers7

14

In C the header file you want is <stdint.h> and the constant is UINT32_MAX

static void update_value(char op)
{
    if (op == '+')
        if ( value < (UINT32_MAX - 1))
            value++;    // uint32_t global value
        else
            printf("too big!\n");
    else
       if (value > 0)
           value--;
       else
           printf("too small!\n");
}

For C++ you can use any number of solutions found here: What's the C++ equivalent of UINT32_MAX?

Community
  • 1
  • 1
Mike
  • 47,263
  • 29
  • 113
  • 177
9

I've found that the most general solution is to check if the incremented value is in fact greater than the previous value, or if the decremented value is smaller than the previous value. This works only if the value is unsigned, independently of the size of the variable, and is pretty much as portable as C code ever gets.

static void update_value(char op)
{
  if (op == '+') {
    if (value + 1 > value) value ++;
  } else {
    if (value - 1 < value) value --;
  }
}

Note that the code may happen to work with signed values, but per the C standard this would be undefined behavior, and the compilers are free to replace if (value + 1 > value) ... with if (1) .... You should not use this code with signed values unless you have a process in place to audit the generated object code after it has been linked.

With gcc and clang, you'd need to add -fwrapv option to let this code work for signed values; with other compilers your mileage may vary.

A sane way of doing this is to be type-specific and use constants from limits.h. For example:

#include "limits.h"

static void update_int(char op, int *value)
{
  int val = *value; // ignoring NULL pointer dereference

  if (op == '+') {
    if (val != INT_MAX) *value = val + 1;
  } else {
    if (val != INT_MIN) *value = val - 1;
  }
}

static void update_int(char op, unsigned int *value)
{
  unsigned int val = *value; // ignoring NULL pointer dereference

  if (op == '+') {
    if (val != UINT_MAX) *value = val + 1;
  } else {
    if (val != UINT_MIN) *value = val - 1;
  }
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
4

Maybe you are looking for <limits>: http://www.cplusplus.com/reference/limits/numeric_limits/

You can do something like this to get what you want:

unsigned int n = numeric_limits<unsigned int>::max()

You also have this <cstdint>: http://www.cplusplus.com/reference/cstdint/

UINTN_MAX: Maximum value of exact-width unsigned type (Exactly 2^N-1)

hinafu
  • 689
  • 2
  • 5
  • 13
2

If you're using C, you're looking for limits.h. The macro you want is UINT_MAX.

If you're in the C++ world, you want std::numeric_limits<uint32_t>::max().

Dan
  • 12,409
  • 3
  • 50
  • 87
2

Check #include <stdint.h> and http://en.wikipedia.org/wiki/C_data_types#Fixed_width_integer_types

What you are looking for are UINT32_MAX.

Sergey L.
  • 21,822
  • 5
  • 49
  • 75
0
static void update_value(char op)
{
    if (op == '+')
        if (value == UINT_MAX)
            printf("Maximum value achieved.\n");
        else
            value ++;
    else
       if (value == 0)
           printf("Minimum value achieved.\n");
       else
           value --;
}

UINT_MAX, for this constant you have to include limits.h

Adeel Ahmed
  • 1,591
  • 8
  • 10
-1

You need limits.h (INT_MIN and INT_MAX) : more info here : http://www.cplusplus.com/reference/climits/

Joze
  • 1,285
  • 4
  • 19
  • 33