I am working with embedded device, with 32K of memory, writing in plain C using IAR EWARM v6.30.
To make code more readable I would like to define some enum types, for example, something like
{RIGHT_BUTTON, CENTER_BUTTON, LEFT_BUTTON}
instead of using 0, 1, 2 values, but I am afraid it will take additional memory that is already scarce.
So I have 2 questions: 1) Can I force enum to be of short or byte type intead of int? 2) What is an exact memory imprint of defining enum type?
In fully compliant ISO C the size and type of an enum constant is that of signed int
. Some embedded systems compilers deliberately do not comply with that as an optimisation or extension.
In ISO C++ "The underlying type of an enumeration is an integral type that can represent all the enumerator values defined in the enumeration.", so a compiler is free to use the smallest possible type, and most do, but are not obliged to do so.
In your case (IAR EWARM), the manual clearly states:
No option required, in fact you'd need to use --enum_is_int
to force compliant behaviour. Other compilers may behave differently or have different extensions, pragmas or options to control this. Such things will normally be defined in the documentation.
"The identifiers in an enumerator list are declared as constants that have type int and may appear wherever such are permitted."
but also that "Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration."
Lundin 2012-04-05 11:45
|
for example, you end up with an integer that is no-longer an enum value (unless you exhaustively define all possible combinations!), and certainly no longer has enum type. Use const
, #define
or struct
bit-fields instead as appropriate. Either way - you have asked a question in a comment to a barely related issue - post a new question rather then commenting on three year old answers. By commenting on this answer, you are asking only me when you could be asking all or SO - Clifford 2015-08-03 11:12
If you really need to keep the data size down to a char
then you can always use a set of #define
constant values to represent the enum
states and only ever use these values in the your assignments and tests.
For a conforming compiler, an enumerated constant is always of type int
(equivalently, signed int
). But such constants aren't typically stored in memory, so their type probably won't have much effect on memory requirements.
A declared object of the enumerated type is of the enumerated type itself, which is compatible with char
or with some signed or unsigned integer type. The choice of type is implementation-defined (i.e., the compiler gets to choose, but it must document how it makes the choice); the only requirement is that the type has to be capable of storing the values of all the constants.
It's admittedly odd that the constants are of type int
rather than the enumerated type, but that's how the language is defined (the reasons are historical, and C++ has different rules).
For example, given:
enum foo { x, y, z };
enum foo obj;
obj = z;
the expression z
is of type int
and has the value 2 (just like the decimal constant 2
), but the object obj
is of type enum foo
and may be as small as one byte, depending on the compiler. The assignment obj = z;
involves an implicit conversion from int
to enum foo
(that conversion may or may not require additional code).
Some compilers may provide some non-standard way to specify the type to be chosen for an enumerated type. Some may even violate the standard in some way. Consult your compiler's documentation, print out the value of sizeof (enum foo)
, and, if necessary, examine the generated code.
It's likely that your compiler will make reasonable decisions within the constraints imposed by the language. For a compiler targeted at memory-poor embedded systems, it's particularly likely that the compiler will either choose a small type, or will let you specify one. Consult your compiler's documentation.
As Ian's answer suggests, if you want to control memory usage yourself, you can use char
or unsigned char
objects. You can still use an enum
definition to define the constants, though. For example:
enum { x, y, z }; // No tag, so you can't declare objects of this type
typedef unsigned char foo; // an enum_foo object is guaranteed to be 1 byte
foo obj = z;
Reference: section 6.7.2.2 of the C standard. The link is to a 1.7-megabyte PDF of a recent draft of the 2011 ISO C standard; this particular section hasn't changed significantly since 1989.
An ANSI C compiler will always represent an enum as an int
to represent variables of type enum
.
http://en.wikipedia.org/wiki/Enumerated_type#C_and_syntactically_similar_languages
One option to use int
s in your program would be to use them to define values, but cast to char
when actually used
char value = (char)Buttons.RIGHT_BUTTON;