Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

In fact, -1 is implicitly cast to its equivalente unsigned value when it is assigned to nextValue. The equivalente unsigned is the value with the same bitwise representation (which is 111111111111..., this is, the maximum unsigned value).

Later on, in the comparison statement, another implicit cast happens.

So this works right now, but may cause problem in the future. It is never a good idea to mix signed and unsigned values.

Yes, I believe enums are signed. Change

unsigned int nextIndex;

to

int nextIndex;

and your program should work.

The C++ standard allows an implementation to use a signed type for enums but does not require it. Therefore, you cannot in general assume that it is safe to put negative numbers into an enum.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top