The typecast to unsigned int or the suffix u/U is needed for the values 0x00, 0x01, and 0x02 in many contexts. 0x00, 0x01 and 0x02 by themselves are constants of type int, and there are some bit twiddling things that works dubiously on ints, for example when bit shifting them to the sign position!
And that would happen if you take the value 0x02 (int) and left-shift that to the bits 31:30! So,
0x02 << 30
has undefined behaviour on machines where ints are 32 bits wide, whereas
0x02U << 30
or
((uint32_t)0x02) << 30
would not.
The identifiers of the enum list are declared as (C11 6.7.2.2p3)
constants that have type int and may appear wherever such are permitted.
i.e. yes, they too would need the casts for those bit shifts.
Do note that the type of the enumeration constants in C need not be the type of the enumeration itself:
#include <stdio.h>
enum foo {
bar = 42
};
int main(void) {
printf("An enumeration constant is an %s\n",
_Generic(bar,
int: "int",
unsigned int: "unsigned int",
default: "something else"));
printf("On this implementation the enum foo is %s\n",
_Generic((enum foo) 0,
int: "int",
unsigned int: "unsigned int",
default: "something else"));
}
On GCC this will print int for the enumeration constant type, and unsigned int for the type of enum foo. I.e. the constant has a different type than the actual enumeration would have.
Also, using an enumeration constant that is outside the range of an integer is a constraint violation; as 0x80000000 is not representable as an int on 32-bit systems, it cannot be used as an enumeration constant portably:
% gcc enumtest.c -std=c11 -pedantic
enumtest.c:5:11: warning: ISO C restricts enumerator values to range of ‘int’
[-Wpedantic]
5 | bar = 0x80000000
| ^~~~~~~~~~
Finally, as the C standard says that the type of the enum itself is left to the compiler decide, some compilers might use unsigned char for short enums. Well, you might need a cast even there, because unsigned char will be promoted to a signed int, not unsigned int before arithmetic.