4

How can I define the type of an enum to be uint8 instead of int?

typedef enum
{
  R_DIRECTION_LEFT = 1,
  R_DIRECTION_RIGHT = 2,
  R_DIRECTION_TOP = 4,
  R_DIRECTION_BOTTOM = 8
} R_Direction;
Lundin
  • 195,001
  • 40
  • 254
  • 396
Ronen333
  • 69
  • 1
  • 8

5 Answers5

4

No you can't.

From standard §6.4.4.3 C11 standard N1570

An identifier declared as an enumeration constant has type int.

user2736738
  • 30,591
  • 5
  • 42
  • 56
  • 2
    It might be worth noting that an enum does not have any storage requirements. It is only when you _use_ an enum, or store an enum value somewhere, that it makes a difference. – Dúthomhas Feb 06 '18 at 17:28
2

The identifiers in an enum list have type int, as per §6.7.2.2 3 of the C11 Standard:

The identifiers in an enumerator list are declared as constants that have type int and may appear wherever such are permitted.

But, enumerations constitute distinct types §6.2.5 16:

Each distinct enumeration constitutes a different enumerated type.

Of the enumerated type itself, the Standard says in §6.7.2.2 4 only 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.

Further, in a footnote it is pointed out that:

An implementation may delay the choice of which integer type until all enumeration constants have been seen.

So the type of an enumeration is distinct, and this type must be compatible with one of char, a signed integer type, or an unsigned integer type. Which of these will be used is implementation-defined, and may vary from case to case on the same implementation.

ad absurdum
  • 19,498
  • 5
  • 37
  • 60
1

If you use GCC, you can use __attribute__ ((packed)) to reduce the size of variables of this type. From here:

This [packed] attribute, attached to an enum, struct, or union type definition, specified that the minimum required memory be used to represent the type.

Since your enum only has values in range from 0 to 255, it will fit in a single byte when this attribute is applied.

There's a related compiler option:

Specifying the -fshort-enums flag on the [command] line is equivalent to specifying the packed attribute on all enum definitions.

kfx
  • 8,136
  • 3
  • 28
  • 52
  • 1
    Note, though, that the use of `__attribute__ ((packed))` can, on some platforms, [result in code that doesn't run](https://stackoverflow.com/questions/43559712/android-ndk-c-struct-member-access-causes-sigbus-signal-sigbus-illegal-ali). – Andrew Henle Feb 06 '18 at 17:33
  • @AndrewHenle don't see the connection with my answer. The question you linked shows code that does not run because of unaligned access. Furthermore, if that person has used `packed`, the could run, as the compiler would be aware that the fields can be unaligned. – kfx Feb 06 '18 at 17:36
  • 1
    `__attribute__ ((packed))` not only produces non-portable code, it's not safe. See https://groups.google.com/forum/#!topic/android-ndk/1CnDAWh6-t0 and https://stackoverflow.com/questions/8568432/is-gccs-attribute-packed-pragma-pack-unsafe for just a couple of examples. Just Google "attribute packed sigbus". The x86 paradigm of "I can access memory any way I want without penalty" does not apply to other platforms. As some of those examples demonstrate, GCC isn't all that good on ARM (and SPARC, too) at properly aligned memory access when using `packed`. – Andrew Henle Feb 06 '18 at 17:45
  • Not an issue as long as the structure is not accessed by external pointers. If it is, use `-Wcast-align` so that compiler warns you if the alignment of the pointer is different (e.g. without the `packed` attribute). – kfx Feb 06 '18 at 17:47
  • 1
    *Not an issue as long as the structure is not accessed by external pointers.* Not true. Did you read the examples I posted? – Andrew Henle Feb 06 '18 at 17:49
  • Yes, they say: "It's perfectly safe as long as you always access the values through the struct via the . (dot) or -> notation." – kfx Feb 06 '18 at 17:51
  • And I can say I have a pet unicorn. Read some of these problems: https://www.google.com/search?q=attribute+packed+sigbus – Andrew Henle Feb 06 '18 at 17:52
  • What exactly was your point when linking to the examples that don't support your opinion, then? ;) – kfx Feb 06 '18 at 17:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/164638/discussion-between-kfx-and-andrew-henle). – kfx Feb 06 '18 at 18:00
  • The OP did not mention a specific compiler, so how to do this in a non-portable way on a specific compiler isn't relevant. – Lundin Feb 07 '18 at 07:54
0

How can I define the type of an enum to be uint8 instead of int?

You can't. Per 6.7.2.2 Enumeration specifiers, paragraph 2, of the C standard:

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

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
0

As already mentioned in other answers, there is no standard way to solve this, since the standard says that enumeration constants are int. The types of enumeration constants and variables is a known major flaw in the language.

The solution is simply to cast the enumeration constant into uint8_t whenever using it. When the size and signedness of a value matters, it might be best to avoid enums entirely. #define or const can be used to create type-safe alternatives.

Lundin
  • 195,001
  • 40
  • 254
  • 396