Reputation: 2169
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?
Upvotes: 4
Views: 5428
Reputation: 5480
Check out the discussion thread at the end of this article.
http://embeddedgurus.com/barr-code/2011/06/is-uint16_t-1-portable-c-code/
The upshot is that (unsigned)(-1) is perfectly legal and is guaranteed to have the maximum value for that type, regardless of actual width or internal representation.
Whether or not it's a good idea is another question. Personally, I prefer the solution offered by Johnsyweb.
As to whether or not you always need the cast, that's going to be compiler dependent. Since you've tried VS and GCC, it seems so.
Upvotes: 1
Reputation: 2169
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:
unsigned(-1)
.~0U
, which, on a two's compement machine, takes 0
and then negates each bit, which gives the largest representable unsigned number.UINT_MAX
which is effectively #define
d as unsigned(-1)
.-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.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.Upvotes: 6
Reputation: 141770
By its very nature, you cannot write negative one as an unsigned literal in C++ or any other language.
You don't mean -1
, you mean std::numeric_limits<unsigned int>::max()
.
#include <iostream>
#include <limits>
int main()
{
unsigned a = std::numeric_limits<unsigned int>::max();
if (a == std::numeric_limits<unsigned int>::max())
{
std::cout << "check " << a << "\n";
}
}
The C++11 standard made this function constexpr
, which guarantees that the function is a compile-time constant. (Further reading).
If you want to avoid calculating this for every iteration of a loop using an older compiler, create a const
outside the loop and compare this:
const unsigned int magic_number = std::numeric_limits<unsigned int>::max();
// [...]
if (a == magic_number)
Upvotes: 6
Reputation: 4996
How about just using ULONG_MAX? You need to include limits.h.
Alternatively, you can also use 0xFFFFFFFF -- properly defined in a macro or static constant, of course.
Upvotes: 0
Reputation: 2813
I think you should not mess unsigned and signed. -1 is Signed and should stay in that way, maybe it is a design problem that you want to have -1 often. There are solutions like boost::optional.
http://www.boost.org/doc/libs/1_49_0/libs/optional/doc/html/index.html
example:
#include <boost/optional.hpp>
#include <iostream>
boost::optional<int> find (const std::string& s, char t)
{
for (int i = 0 ; i < s.length () ; ++ i)
if (s [i] == t)
return i ;
return boost::optional<int>() ;
}
int main (int argc, char* argv[])
{
std::string s = argv[1] ;
char t = *argv[2] ;
boost::optional<int> idx = find (s, t) ;
if (idx)
std::cout << "found at " << *idx << std::endl ;
else
std::cout << "not found" << std::endl ;
return 0 ;
}
Upvotes: 0
Reputation: 2481
To avoid having to deal with the length of an int, you can use
~0
This gives you all ones, which on a twos-complement machine (are there any others still these days?) is the same as -1. But it is a legit unsigned long.
Upvotes: 2