Search code examples
c++literalsunsigned

How to write negative one as an unsigned literal in C++


In my program, I often use -1 (aka UINT_MAX) as a value for unsigned variables to denote something special. I also compare against this value. Turning on higher levels of warning messages reveals that compilers (both VS and GCC) do not like this syntax.

// warning C4245: 'initializing' : conversion from 'int' to 'unsigned int', signed/unsigned mismatch
unsigned a = -1;

// warning C4146: unary minus operator applied to unsigned type, result still unsigned
unsigned b = -1U;

// fine but messy
unsigned c = unsigned(-1);

// no warning on VS, signed/unsigned comparison warning with GCC
if (a == -1)
{
  std::cout << "check\n";
}

Question 1: Is the syntax given above (each case) legitimate C++ code?

Question 2: Do I really have to write unsigned(-1) everywhere I use this value to assign/compare to an unsigned int or is there a cleaner way that will not trigger a compiler warning?


Solution

  • Answer 1:

    Yes, they are both proper, albeit arguably unpleasant, C++ constructs.

    • -1 is interpreted as an int literal. It is proper C++ syntax, as the standard allows for implicit int to unsigned int conversion, but the compiler warns when this implicit conversion is used at higher warning levels.
    • -1U is intepreted as -(1U). Taking the negative of an unsigned int is proper C++ syntax, as the compiler performs this operation modulo (UINT_MAX + 1), however the compiler issues a warning letting you know.
    • (unsigned(-1) == -1) is also proper syntax, as the compiler implicitly converts -1 to unsigned(-1) for the comparison. It does warn you about the implicit conversion at higher warning levels to let you know it has done so.

    Answer 2:

    There are several options to write or effect unsigned(-1) as a literal:

    • Write unsigned(-1).
    • Write ~0U, which, on a two's compement machine, takes 0 and then negates each bit, which gives the largest representable unsigned number.
    • Write UINT_MAX which is effectively #defined as unsigned(-1).
    • If assigned or comparing to an unsigned value, write -1 and let the compiler do the implicit conversion and cope with the warning messages. However, it should be noted that -1 is an int literal and only gets converted to unsigned based on its function in the code.
    • Write std::numeric_limits<unsigned>::max() which is a function which returns unsigned(-1). Note that in In C++11 this function will be a constexpr which a good compiler should always simplify into a literal. VC++ currently simplifies this away into unsigned(-1) for non-debug builds. It is, however, a value returned from a function call and not a literal.