Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ enum to unsigned int comparison

I found this in the code I'm working on at the moment and thought it was the cause of some problems I'm having.

In a header somewhere:

enum SpecificIndexes{
    //snip
    INVALID_INDEX = -1
};

Then later - initialization:

nextIndex = INVALID_INDEX;

and use

if(nextIndex != INVALID_INDEX)
{
    //do stuff
}

Debugging the code, the values in nextIndex didn't quite make sence (they were very large), and I found that it was declared:

unsigned int nextIndex;

So, the initial setting to INVALID_INDEX was underflowing the unsigned int and setting it to a huge number. I assumed that was what was causing the problem, but looking more closely, the test

if(nextIndex != INVALID_INDEX)

Was behaving correctly, i.e, it never executed the body of the if when nextIndex was the "large +ve value".

Is this correct? How is this happening? Is the enum value being implicitly cast to an unsigned int of the same type as the variable, and hence being wrapped in the same way?


2 Answers

Yes to everything. It is valid code, it is also commonly used library-side C++ code, more so in modern C++ (it is strange when you see it the first time but its a very common pattern in reality).

Then enums are signed ints, but they get implicitly cast into unsigned ints, now this depending on your compiler might give a warning, but its still very commonly used, however you should explicitly cast to make it clear to maintainers.

like image 103
Robert Gould Avatar answered Apr 21 '26 06:04

Robert Gould


enums may be represented by signed or unsigned integral types according to whether they contain any negative values and what the compiler feels like. The example here contains a negative value and hence must be represented by a signed integral type.

Equality comparison between signed and unsigned types is safe and usually does what the author intended - the signed value will be converted to unsigned first, and the result of doing that is defined by the C++ standard and is intuitive (at least, it is once you know the destination type. Except maybe if integers aren't two's complement. So maybe not that intuitive, but it doesn't normally cause problems).

Order comparison is more likely to result in errors. For example:

SpecificIndexes value = INVALID_VALUE;
return (value >= 0);

returns false, but:

unsigned int value = INVALID_VALUE;
return (value >= 0);

returns true. Sometimes the author will not appreciate the difference, especially if the type of "value" isn't quite so obvious at the point of use. The compiler may well warn about the second example, though, because (value >= 0) is a tautology.

like image 27
2 revsSteve Jessop Avatar answered Apr 21 '26 06:04

2 revsSteve Jessop