7

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.
Community
  • 1
  • 1
Thomas Matthews
  • 52,985
  • 12
  • 85
  • 144
  • 1
    To be clear, is C++ an option? – Richard J. Ross III Jul 03 '12 at 15:50
  • I wish. I could create an actual type if they let us use C++. :-( – Thomas Matthews Jul 03 '12 at 16:03
  • `REGISTER_STATUS_BIT = ~0x7fffffff`? – Daniel Fischer Jul 03 '12 at 16:11
  • @DanielFischer: Is this portable? Please submit as an answer. – Thomas Matthews Jul 03 '12 at 16:16
  • @DanielFisher: ~0x7fffffff is just as portable as -2147483648 is. They evaluate to the same bit pattern. The same caveats I outlined in my answer apply. – Nominal Animal Jul 03 '12 at 16:28
  • @NominalAnimal The bit-complement could work on ones' complement machines where -2147483648 wouldn't. So it might be a tiny bit more portable. I'd mainly prefer it because it makes the bit pattern obvious, though. – Daniel Fischer Jul 03 '12 at 17:39
  • @DanielFischer I haven't seen an one's complement architecture in two decades, but you are correct. ;) I do agree, ~0x7fffffff is a bit easier to read/understand than -2147483648. Other than that, I'd go with what I recommended in my answer below, especially the conditional part. – Nominal Animal Jul 03 '12 at 17:42
  • @NominalAnimal I think I recently read that one or two ones' complement systems are still around. But in practice, I think systems where `int` is 64 bits will become what breaks -2147483648 before either of us encounters a ones' complement box. – Daniel Fischer Jul 03 '12 at 17:52
  • @DanielFischer Agreed. That's why I recommend '#if defined(\_\_ICCARM\_\_) && \_\_WORDSIZE == 32' (or whatever the OP's compiler provides) around the workaround, and defaulting to 1<<31 otherwise. – Nominal Animal Jul 03 '12 at 18:04

4 Answers4

4

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

ouah
  • 134,166
  • 14
  • 247
  • 314
  • 1
    Which means what in the context of this question? – Richard J. Ross III Jul 03 '12 at 15:51
  • Can the `enum` constant be declared as `unsigned`? – Thomas Matthews Jul 03 '12 at 15:58
  • @ThomasMatthews no, they are always of type `int`. – ouah Jul 03 '12 at 15:59
  • Sorry, I downvoted because I thought that an `enum` type being `unsigned int` contradicted the C standard, but I was mistaken. C99 §6.7.2.2/4 says it's implementation-defined (only the *constants* are required to be `int`). If you edit, I will remove the downvote (can't remove it now since it's too old). – Adam Rosenfield Jul 05 '12 at 16:04
  • @AdamRosenfield Thank you to come back on this. I edited by adding a footnote link to the `gcc` implementation-defined documentation on `enum` types. – ouah Jul 05 '12 at 17:11
  • 1
    Gcc seems to support `enum`s _bigger_ than an `int`: see http://stackoverflow.com/a/9524663/318716. – Joseph Quinsey Nov 06 '12 at 08:20
2

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;
Nominal Animal
  • 34,734
  • 4
  • 49
  • 79
  • IAR enum types are different. see "--enum-is-int" in it's help. Nevertheless, I could not find a way to make enum an unsigned type – lkanab Aug 03 '15 at 06:51
  • @lkanab: If you enable the IAR language extensions (using the `-e` command-line option), then you can use e.g. `typedef enum hardware_register_e { REGISTER_STATUS_BIT = 0x80000000UL } hardware_register_t;` in which case the enum will be of type `unsigned long`. See pages 169 and 211 of the [IAR C/C++ Development Guide for ARM](http://supp.iar.com/FilesPublic/UPDINFO/004916/arm/doc/EWARM_DevelopmentGuide.ENU.pdf). I've added a more detailed answer to the [question](http://stackoverflow.com/questions/31780026/bitwise-operation-with-signed-enum-value) you've asked I think you're referring to. – Nominal Animal Aug 04 '15 at 07:22
1

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.

Adam Rosenfield
  • 360,316
  • 93
  • 484
  • 571
1

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)
vitaut
  • 37,224
  • 19
  • 144
  • 248