Are C++ enums signed or unsigned?

C++Enums

C++ Problem Overview


Are C++ enums signed or unsigned? And by extension is it safe to validate an input by checking that it is <= your max value, and leave out >= your min value (assuming you started at 0 and incremented by 1)?

C++ Solutions


Solution 1 - C++

Let's go to the source. Here's what the C++03 standard (ISO/IEC 14882:2003) document says in 7.2-5 (Enumeration declarations):

> The underlying type of an enumeration > is an integral type that can represent > all the enumerator values defined in > the enumeration. It is > implementation-defined which integral > type is used as the underlying type > for an enumeration except that the > underlying type shall not be larger > than int unless the value of an > enumerator cannot fit in an int or > unsigned int.

In short, your compiler gets to choose (obviously, if you have negative numbers for some of your ennumeration values, it'll be signed).

Solution 2 - C++

You shouldn't rely on any specific representation. Read the following link. Also, the standard says that it is implementation-defined which integral type is used as the underlying type for an enum, except that it shall not be larger than int, unless some value cannot fit into int or an unsigned int.

In short: you cannot rely on an enum being either signed or unsigned.

Solution 3 - C++

You shouldn't depend on them being signed or unsigned. If you want to make them explicitly signed or unsigned, you can use the following:

enum X : signed int { ... };    // signed enum
enum Y : unsigned int { ... };  // unsigned enum

Solution 4 - C++

You shouldn't rely on it being either signed or unsigned. According to the standard it is implementation-defined which integral type is used as the underlying type for an enum. In most implementations, though, it is a signed integer.

In C++0x strongly typed enumerations will be added which will allow you to specify the type of an enum such as:

enum X : signed int { ... };    // signed enum
enum Y : unsigned int { ... };  // unsigned enum

Even now, though, some simple validation can be achieved by using the enum as a variable or parameter type like this:

enum Fruit { Apple, Banana };

enum Fruit fruitVariable = Banana;  // Okay, Banana is a member of the Fruit enum
fruitVariable = 1;  // Error, 1 is not a member of enum Fruit
                    // even though it has the same value as banana.

Solution 5 - C++

Even some old answers got 44 upvotes, I tend to disagree with all of them. In short, I don't think we should care about the underlying type of the enum.

First off, C++03 Enum type is a distinct type of its own having no concept of sign. Since from C++03 standard dcl.enum

7.2 Enumeration declarations 
5 Each enumeration defines a type that is different from all other types....

So when we are talking about the sign of an enum type, say when comparing 2 enum operands using the < operator, we are actually talking about implicitly converting the enum type to some integral type. It is the sign of this integral type that matters. And when converting enum to integral type, this statement applies:

9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5).

And, apparently, the underlying type of the enum get nothing to do with the Integral Promotion. Since the standard defines Integral Promotion like this:

4.5 Integral promotions conv.prom
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long.

So, whether an enum type becomes signed int or unsigned int depends on whether signed int can contain all the values of the defined enumerators, not the underlying type of the enum.

See my related question https://stackoverflow.com/questions/24802322/sign-of-c-enum-type-incorrect-after-converting-to-integral-type

Solution 6 - C++

The compiler can decide whether or not enums are signed or unsigned.

Another method of validating enums is to use the enum itself as a variable type. For example:

enum Fruit
{
    Apple = 0,
    Banana,
    Pineapple,
    Orange,
    Kumquat
};

enum Fruit fruitVariable = Banana;  // Okay, Banana is a member of the Fruit enum
fruitVariable = 1;  // Error, 1 is not a member of enum Fruit even though it has the same value as banana.

Solution 7 - C++

In the future, with C++0x, strongly typed enumerations will be available and have several advantages (such as type-safety, explicit underlying types, or explicit scoping). With that you could be better assured of the sign of the type.

Solution 8 - C++

In addition to what others have already said about signed/unsigned, here's what the standard says about the range of an enumerated type:

7.2(6): "For an enumeration where e(min) is the smallest enumerator and e(max) is the largest, the values of the enumeration are the values of the underlying type in the range b(min) to b(max), where b(min) and b(max) are, respectively, the smallest and largest values of the smallest bitfield that can store e(min) and e(max). It is possible to define an enumeration that has values not defined by any of its enumerators."

So for example:

enum { A = 1, B = 4};

defines an enumerated type where e(min) is 1 and e(max) is 4. If the underlying type is signed int, then the smallest required bitfield has 4 bits, and if ints in your implementation are two's complement then the valid range of the enum is -8 to 7. If the underlying type is unsigned, then it has 3 bits and the range is 0 to 7. Check your compiler documentation if you care (for example if you want to cast integral values other than enumerators to the enumerated type, then you need to know whether the value is in the range of the enumeration or not - if not the resulting enum value is unspecified).

Whether those values are valid input to your function may be a different issue from whether they are valid values of the enumerated type. Your checking code is probably worried about the former rather than the latter, and so in this example should at least be checking >=A and <=B.

Solution 9 - C++

Check it with std::is_signed<std::underlying_type + scoped enums default to int

https://en.cppreference.com/w/cpp/language/enum implies:

main.cpp

#include <cassert>
#include <iostream>
#include <type_traits>

enum Unscoped {};
enum class ScopedDefault {};
enum class ScopedExplicit : long {};

int main() {
    // Implementation defined, let's find out.
    std::cout << std::is_signed<std::underlying_type<Unscoped>>() << std::endl;

    // Guaranteed. Scoped defaults to int.
    assert((std::is_same<std::underlying_type<ScopedDefault>::type, int>()));

    // Guaranteed. We set it ourselves.
    assert((std::is_same<std::underlying_type<ScopedExplicit>::type, long>()));
}

GitHub upstream.

Compile and run:

g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main

Output:

0

Tested on Ubuntu 16.04, GCC 6.4.0.

Solution 10 - C++

While some of the above answers are arguably proper, they did not answer my practical question. The compiler (gcc 9.3.0) emitted warnings for:

enum FOO_STATUS {
    STATUS_ERROR = (1 << 31)
};

The warning was issued on use:

unsigned status = foo_status_get();
if (STATUS_ERROR == status) {

(Aside from the fact this code is incorrect ... do not ask.)

When asked properly, the compiler does not emit an error.

enum FOO_STATUS {
    STATUS_ERROR = (1U << 31)
};

Note that 1U makes the expression unsigned.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMattView Question on Stackoverflow
Solution 1 - C++Michael BurrView Answer on Stackoverflow
Solution 2 - C++zvrbaView Answer on Stackoverflow
Solution 3 - C++Adam RosenfieldView Answer on Stackoverflow
Solution 4 - C++MattView Answer on Stackoverflow
Solution 5 - C++JavaManView Answer on Stackoverflow
Solution 6 - C++Cristián RomoView Answer on Stackoverflow
Solution 7 - C++Kris KumlerView Answer on Stackoverflow
Solution 8 - C++Steve JessopView Answer on Stackoverflow
Solution 9 - C++Ciro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 10 - C++Preston L. BannisterView Answer on Stackoverflow