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:

  1. The preference is not to expand to 64 bits (because the code resides in an embedded system).
  2. Due to skill limitations, C++ is not allowed for this project. :-(

Edit 2:

  • Compiler is IAR Embedded Workbench for ARM7.
Was it helpful?

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 #defines 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)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top