2

I'm trying to obtain the maximum value of a certain unsigned integer type without including any headers like <limits>. So I thought I'd simply flip the bits of the unsigned integer value 0.

#include <iostream>
#include <limits>

int main()
{
    std::cout << (~0U) << '\n'; // #1
    std::cout << (std::numeric_limits< unsigned >::max()) << '\n'; // #2
    return 0;
}

I'm not very experienced on the subtle differences between these. Which is why I'm asking if some unexpected behavior or some platform/architecture issues could occur by using the first method.

SLC
  • 2,167
  • 2
  • 28
  • 46
  • 3
    `~0U` is fine . – M.M Oct 05 '16 at 01:38
  • 1
    The standard doesn't guarantee a two's complement integer representation, so this trick is not portable, strictly speaking. In practice, it will probably always work, but you should prefer to cast `0` to the expected type instead of specifying as `0U`, which is `unsigned int`. For example, `unsigned long long b = ~0U;` gives you the incorrect maximum `unsigned long long` value when `int` uses fewer bits than `long long`. – Christopher Oicles Oct 05 '16 at 01:40
  • @ChristopherOicles Thanks for the suggestion. I'm actually using a `~static_cast< unsigned ... >(0)` to a type with the proper size. – SLC Oct 05 '16 at 01:51
  • 1
    Suggest `std::cout << ((unsigned type of your choosing) -1) << '\n';` or `static_cast` – chux - Reinstate Monica Oct 05 '16 at 02:00
  • 1
    An answer to this question references the new standard which seems to seems to support chux's idea of casting `-1`: http://stackoverflow.com/questions/21769068/casting-negative-integer-to-larger-unsigned-integer – Christopher Oicles Oct 05 '16 at 02:08
  • 1
    @ChristopherOicles there are no negative numbers in this question, so it does not matter whether 2's complement representation of negative numbers is used or not – M.M Oct 05 '16 at 02:32
  • @M.M I misused "Two's Complement" as an easy way to specify the standard binary encoding used by all existing compilers, however the standard only requires integers to be encoded in a way such that each bit pattern corresponds to a unique value inside the range determined by the type's bit count -- so the standard only requires that inverting all bits in an unsigned integer zero must result in a value which is not zero. – Christopher Oicles Oct 05 '16 at 06:22
  • @ChristopherOicles the standard requires "pure binary" representation, it's hard to interpret that to mean anything ither than 1=1, 10=2, 11=3, 100=4, etc. I'm not convinced that it's permitted for UINT_MAX to be something other than one less than a multiple of 2 , but that discussion is too big for the comment section! – M.M Oct 05 '16 at 11:54
  • @ChristopherOicles Unsigned types have the specification "If there are N value bits, each bit shall represent a different power of 2 between 1 and pow(2,N−1), so that objects of that type shall be capable of representing values from 0 to pow(2,N−1) using a pure binary representation" See C11 6.2.6.2 A value with all bits set must be the maximum value. – chux - Reinstate Monica Oct 05 '16 at 13:58
  • Possible duplicate of [Is it safe to use -1 to set all bits to true?](http://stackoverflow.com/questions/809227/is-it-safe-to-use-1-to-set-all-bits-to-true), although there the problem is treated only for unsigned int type. – Antonio Oct 06 '16 at 08:22

2 Answers2

5

... to obtain the maximum value of a certain unsigned integer type without including any headers

Simply assign the value -1

unsigned_type_of_choice max = -1;

Conversion of the -1, which is an int, to any unsigned type results in the value of number that is one greater than the largest value minus 1.

The following does not provide the maximum value of the destination type. It fails when the destination type range exceed the range of unsigned, which is the type of ~0U. @Christopher Oicles

// problem
unsigned_type_of_choice max_wannabe = ~0U;
Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • The documentation for this (defined) behaviour is quoted [here](http://stackoverflow.com/a/2711560/2436175). [Here](http://en.cppreference.com/w/cpp/language/implicit_conversion) is much clearer. – Antonio Oct 05 '16 at 16:18
  • That documentation is C++. My goal was a C/C++ solution. – chux - Reinstate Monica Oct 06 '16 at 02:39
  • Sure! To be super diligent one find corresponding sections in both standards, but it becomes really too much effort. Anyway, for C one can reference [here](http://stackoverflow.com/questions/50605/signed-to-unsigned-conversion-in-c-is-it-always-safe). I didn't go too deep, but, although leading to the same result, the mechanisms described for C and C++ differ. – Antonio Oct 06 '16 at 08:04
3

You shouldn't assign ~0U to just any unsigned type, chux's answer already explains why.

For C++, with the following you can get the maximum possible value for all unsigned types.

template <typename T>
T max_for_unsigned_type() {
    return ~(static_cast<T> (0));
}

You are negating a zero of your exact type. I use a verbose function name because it shouldn't be used for signed values. The problem is that for checking signedness the easiest way would be including an extra header, namely type_traits. This other answer then would be useful.

Usage:

max_for_unsigned_type<uint8_t> ();
max_for_unsigned_type<uint16_t> ();
max_for_unsigned_type<uint32_t> ();
max_for_unsigned_type<uint64_t> ();
max_for_unsigned_type<unsigned> ();

Values returned: (see test code here)

255
65535
4294967295
18446744073709551615
4294967295

Note: Doing it for signed types is much more difficult, see Programmatically determining max value of a signed integer type.

Community
  • 1
  • 1
Antonio
  • 19,451
  • 13
  • 99
  • 197