What Is the Size of an Enum Type Data in C++

What is the size of an enum in C?

An enum is only guaranteed to be large enough to hold int values. The compiler is free to choose the actual type used based on the enumeration constants defined so it can choose a smaller type if it can represent the values you define. If you need enumeration constants that don't fit into an int you will need to use compiler-specific extensions to do so.

what is the size of an enum type data in C++?

In your compiler, the size is four bytes because the enum is stored as an int. With only 12 values, you really only need 4 bits, but 32 bit machines process 32 bit quantities more efficiently than smaller quantities.

0 0 0 0  January
0 0 0 1 February
0 0 1 0 March
0 0 1 1 April
0 1 0 0 May
0 1 0 1 June
0 1 1 0 July
0 1 1 1 August
1 0 0 0 September
1 0 0 1 October
1 0 1 0 November
1 0 1 1 December
1 1 0 0 ** unused **
1 1 0 1 ** unused **
1 1 1 0 ** unused **
1 1 1 1 ** unused **

Without enums, you might be tempted to use raw integers to represent the months. That would work and be efficient, but it would make your code hard to read. With enums, you get efficient storage and readability.

Other compilers could use a byte, int16, uint16 int or uint as long as the variable can contain all the values of the enum.

Specifying size of enum type in C

Is there a way to tell your compiler
specifically how wide you want your
enum to be?

In general case no. Not in standard C.

Would it even be worth doing?

It depends on the context. If you are talking about passing parameters to functions, then no, it is not worth doing (see below). If it is about saving memory when building aggregates from enum types, then it might be worth doing. However, in C you can simply use a suitably-sized integer type instead of enum type in aggregates. In C (as opposed to C++) enum types and integer types are almost always interchangeable.

When the enum value is passed to a function, will it be passed as an int-sized value regardless?

Many (most) compilers these days pass all parameters as values of natural word size for the given hardware platform. For example, on a 64-bit platform many compilers will pass all parameters as 64-bit values, regardless of their actual size, even if type int has 32 bits in it on that platform (so, it is not generally passed as "int-sized" value on such a platform). For this reason, it makes no sense to try to optimize enum sizes for parameter passing purposes.

What would be the size of this enum, in bytes? C++

From §7.2/5 of the C++ standard, you have that in your case the underlying type is not fixed:

The underlying type can be explicitly specified using an enum-base. For a scoped enumeration type, the underlying type is int if it is not explicitly specified. In both of these cases, the underlying type is said to be fixed. [...]

Which leads to §7.2/7:

For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can represent all the enumerator values defined in the enumeration. If no integral type can represent all the enumerator values, the enumeration is ill-formed. It is implementation-defined which integral type is used as the underlying type 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. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0.


Summing up, for your enumeration the underlying type is at most an int or unsigned int. You can check the size via sizeof, and the type via typeid. Example checking code that prettifies the result with g++ (not necessary with Visual C++):

#include <iostream>
#include <typeinfo> // std::type_info
#include <type_traits> // std::underlying_type
using namespace std;

int const bits_per_byte = CHAR_BIT;

#ifdef __GNUC__
# include <cxxabi.h> // abi::*, free
# include <string> // std::string

auto display_name( type_info const& info )
-> string
{
int status;
char* demangled = abi::__cxa_demangle( info.name(), 0, 0, &status );
string result = demangled;
free( demangled );
return result;
}
#else
auto display_name( type_info const& info )
-> string
{ return info.name(); }
#endif // __GNUC__

enum Cars {
Toyota, Suzuki, Volkswa, Mitsubish, Alfarome, Holden, Bradleys
};

auto main() -> int
{
using Cars_type = typename underlying_type< Cars >::type;
type_info const& info = typeid( Cars_type );
cout << "This compiler is " << bits_per_byte*sizeof(void*) << "-bit.\n";
cout << "Underlying type is '" << display_name( info ) << "'.\n";
cout << "Size = " << sizeof( Cars ) << " bytes.\n";
}

Output with MinGW g++ (tdm64-1) 5.1.0:


This compiler is 64-bit.
Underlying type is 'unsigned int'.
Size = 4 bytes.

sizeof enum in C language

In C all enums are most of the time integers of type int, which explains why sizeof(Days) == 4 for you.

To know how many values are in an enum you can do something like this:

enum Days            
{
saturday,
sunday,
monday,
tuesday,
wednesday,
thursday,
friday,
NUM_DAYS
};

Then NUM_DAYS will be the number of enumerations in Days.

Note that this will not work if you change the values of an enumeration, for example:

enum Foo
{
bar = 5,
NUM_FOO
};

In the above enum, NUM_FOO will be 6.

Define data type of enum in C for memory

The C standard says that enumeration constants, that is the "members" of the enum, must be compatible with type int. But the enumeration variable itself is allowed to be of other integer types. If you think this doesn't make any sense, it is because it doesn't: the C standard is irrational when it comes to enums.

As for how to pick which integer type an enumeration variable corresponds to, that's unfortunately a decision made by the compiler, not the programmer. On an 8-bit Atmel, an enum variable is either 8 or 16 bits.

Several compilers gives an option to set the size of an enum through non-standard compiler options. To use such features might not be a good idea regardless, as that would make the code non-portable.

However, regardless of the size of an enum, the compiler may (and likely will) optimize expressions where the enum is present, just as it may optimize any expression containing small integer types to not use int for the calculation, as the C standard otherwise mandates through integer promotion.

In case you have very extreme performance requirements, don't use enums, but uint8_t. But if you had extreme performance requirements, then you wouldn't use a hobbyist 8-bit MCU in the first place! So it turns out that your concern is a non-issue.

Go ahead and use enum and let the compiler worry about optimizations.

Constant enum size no matter the number of enumerated values

In both C and C++, the size of an enum type is implementation-defined, and is the same as the size of some integer type.

A common approach is to make all enum types the same size as int, simply because that's typically the type that makes for the most efficient access. Making it a single byte, for example, would save a very minor amount of space, but could require bigger and slower code to access it, depending on the CPU architecture.

In C, enumeration constants are by definition of type int. So given:

enum foo { zero, one, two };
enum foo obj;

the expression zero is of type int, but obj is of type enum foo, which may or may not have the same size as int. Given that the constants are of type int, it tends to be easier to make the enumerated type the same size.

In C++, the rules are different; the constants are of the enumerated type. But again, it often makes the most sense for each enum type to be one "word", which is typically the size of int, for efficiency reasons.

And the 2011 ISO C++ standard added the ability to specify the underlying integer type for an enum type. For example, you can now write:

enum foo: unsigned char { zero, one, two };

which guarantees that both the type foo and the constants zero, one, and two have a size of 1 byte. C does not have this feature, and it's not supported by older pre-2011 C++ compilers (unless they provide it as a language extension).

(Digression follows.)

So what if you have an enumeration constant too big to fit in an int? You don't need 231, or even 215, distinct constants to do this:

#include <limits.h>
enum huge { big = INT_MAX, bigger };

The value of big is INT_MAX, which is typically 231-1, but can be as small as 215-1 (32767). The value of bigger is implicitly big + 1.

In C++, this is ok; the compiler will simply choose an underlying type for huge that's big enough to hold the value INT_MAX + 1. (Assuming there is such a type; if int is 64 bits and there's no integer type bigger than that, that won't be possible.)

In C, since enumeration constants are of type int, the above is invalid. It violates the constraint stated in N1570 6.7.2.2p2:

The expression that defines the value of an enumeration constant shall
be an integer constant expression that has a value representable as an
int.

and so a compiler must reject it, or at least warn about it. gcc, for example, says:

error: overflow in enumeration values

Enum Size in Bytes

The documentation says:

The default underlying type of enumeration elements is int.

Therefore, your data type will have the size of 4 bytes, which is the size of an int.
You can confirm this by using the following command:

Marshal.SizeOf(Enum.GetUnderlyingType(typeof(MMTPCnxNckRsn)));

Whilst you refer to the enum values in source code using a name, they are represented in the code that runs on the machine as integer values. So your comment about string arrays is quite wide of the mark.

I also think you are over-thinking the issue of size. Looking at your other recent question, you seem to be translating a C++ structure to C# for pinvoke. Well, the C# enum will map straight onto the C++ enum. The pinvoke marshaller will look after the sizes and lay them out for you. You do not need to handle that explicitly.



Related Topics



Leave a reply



Submit