Casting enum definition to unsigned int
-
18-06-2021 - |
Question
According to this SO post:
What is the size of an enum in C?
enum types have signed int
type.
I would like to convert an enum definition from signed int
to unsigned int
.
For example, on my platform an unsigned int
is 32-bits wide.
I want to create an enum:
typedef enum hardware_register_e
{
REGISTER_STATUS_BIT = (1U << 31U)
} My_Register_Bits_t;
My compiler is complaining that the above definition is out of range (which it is for a signed int
).
How do I declare unsigned int
enum
values?
Edit 1:
- The preference is not to expand to 64 bits (because the code resides in an embedded system).
- Due to skill limitations, C++ is not allowed for this project. :-(
Edit 2:
- Compiler is IAR Embedded Workbench for ARM7.
Solution
Unfortunately ISO C standard (c99 6.4.4.3) states that the enumeration constants are of type int
. If you compile the above with e.g. gcc -W -std=c89 -pedantic
, it will issue a warning ISO C restricts enumerator values to range of ‘int’ [-pedantic]
. Some embedded compilers may not accept the code at all.
If your compiler is of the pickier variety, you can workaround the issue by using
typedef enum hardware_register_e
{
REGISTER_STATUS_BIT = -2147483648 /* 1<<31, for 32-bit two's complement integers */
} hardware_register_t;
but it works correctly only if int
is 32-bit two's complement type on your architecture. It is on all 32-bit and 64-bit architectures I have ever used or heard of.
Edited to add: ARM7 uses 32-bit two's complement int
type, so the above should work fine. I only recommend you keep the comment explaining that the actual value is 1<<31
. You never know if somebody ports the code, or uses another compiler. If the new compiler issues a warning, the comment on the same line should make it trivial to fix. Personally, I'd wrap the code in a conditional, perhaps
typedef enum hardware_register_e
{
#ifdef __ICCARM__
REGISTER_STATUS_BIT = -2147483648 /* 1<<31, for 32-bit two's complement integers */
#else
REGISTER_STATUS_BIT = 1 << 31
#endif
} hardware_register_t;
OTHER TIPS
According to this SO post: What is the size of an enum in C? enum types have signed int type.
The thing is enum
types can be int
type but they are not int
in C. On gcc
1), enum
types are unsigned int
by default.
enum
constants are int
but enum
types are implementation defined.
In your case the enum
constant is int
but you are giving it a value that does not fit in a int
. You cannot have unsigned int
enum
constants in C as C says they are int
.
1) gcc implementation defined enum type documentation: "Normally, the type is unsigned int if there are no negative values in the enumeration, otherwise int" in http://gcc.gnu.org/onlinedocs/gcc/Structures-unions-enumerations-and-bit_002dfields-implementation.html
Check if your compiler had an option or a pragma to make enums unsigned. If it doesn't, then you'll just have to use a plain unsigned int
(or a fixed-width type such as uint32_t
) instead of an enum, with #define
s used to define the values it can take.
You can't (at least portably) change the type of enum. The standard is clear that an enumeration constant has type int
. To get rid of the warning you can use a cast:
typedef enum hardware_register_e
{
REGISTER_STATUS_BIT = (int)(1U << 31U)
} My_Register_Bits_t;
Possible Alternatives
If this doesn't have to be in a header, you can use a const
object of required type instead of enumeration constant:
const unsigned int REGISTER_STATUS_BIT = (1U << 31);
Otherwise, you can use a define:
#define REGISTER_STATUS_BIT (1U << 31)