Forcing enum to be of a specific size - Page 1
Forum section: electronics / general

author: ricko_uk
author_rank: Super Contributor
timestamp: June 12, 2021, 12:02:49 am
content: Hi,in C, is there a way to force an enum to be of a specific size (i.e. uint32_t or uint16_t)?If not in C, What about C++?Reason for asking is to make it the size of the micro's architecture to ensure that any change to it is an atomic operation (without having to disable interrupts or using critical sections).Thank you

author: ajb
author_rank: Super Contributor
timestamp: June 12, 2021, 12:21:39 am
content: You can used the "packed" attribute on compilers that support it, for example gcc:https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Type-Attributes.htmlHowever this doesn't let you specify a particular size, just that it should use the minimum size that will contain the enumerated values.Alternatively, since enums in C are not really a storage type unto themselves and are basically just defined constants with slightly nicer syntax, you can store them in whatever integer type you want provided it's large enough for the largest value. Enum values are guaranteed to start at 0 and increment by one unless another value is specified, so your max value will be equal to the number values less one unless you specify differently.

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 12, 2021, 02:09:17 am
content: Quote from: ajb on June 12, 2021, 12:21:39 amYes, if you're using C, as was discussed in another thread, enums are not type-checked anyway, so using them as a type for declaring variables/parameters is useless (except for code documentation reasons). So you can use enums to define your constants, and then use another type for actually storing the value.

author: ajb
author_rank: Super Contributor
timestamp: June 12, 2021, 02:58:35 am
content: Also, there's unlikely to be a significant downside to using a type that is smaller than native, so if you can use an 8 bit int to hold the values you need then you can just use that on all architectures and be done with it. There may be a *small* performance penalty for smaller sizes on more complex architectures (like x86), but it's unlikely to be enough to worry about, and there should be no difference on Cortex M.One thing you may want to do is typedef the storage type you want to use separately from the enum. You can still typedef the enum if you want. Typedefing the storage type won't give you any additional type safety (neither will the enum itself!), but it will make it clear that the size is chosen deliberately, and if you need to change that size at any point (because you've added a bunch of enum values, or you have some corner case where the size does matter) you're only changing it in one place. You'll see this in libraries for these exact reasons.

author: Tagli
author_rank: Contributor
timestamp: June 12, 2021, 05:00:03 am
content: In C++, you can choose the underlying type for bothclassical enumsandenum classes.Code:enum class Number : uint8_t {Zero = 0, One = 1, Two = 2};

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 12, 2021, 04:49:33 pm
content: Quote from: Tagli on June 12, 2021, 05:00:03 amI don't know enough C++ for judging if this is right or not. If anyone can tell which C++ std supports that? But if so, that is one nice feature.

author: Tagli
author_rank: Contributor
timestamp: June 12, 2021, 05:07:07 pm
content: It's available since C++11.https://en.cppreference.com/w/cpp/language/enum

author: ricko_uk
author_rank: Super Contributor
timestamp: June 12, 2021, 06:31:11 pm
content: Thank you all!

author: DavidAlfa
author_rank: Super Contributor
timestamp: June 12, 2021, 08:59:48 pm
content: Probably everyone knows this from 1st of programming... Anyways, in normal C you can always cast the enum to an int of any size.Ex. :Code:typedef enum{opt_disable,opt_enable,opt_reset,opt_auto}options_t;options_t opts;int main(){if ((uint8_t)opts == opt_disable){printf("Option: Disabled, enabling....\r\n");opts = opt_enable;}return 0;}Also gcc has it's own "attributes":https://gcc.gnu.org/onlinedocs/gcc-3.3.2/gcc/Type-Attributes.html#Type%20Attributes

author: ajb
author_rank: Super Contributor
timestamp: June 12, 2021, 09:49:15 pm
content: I'm not sure what you're expecting the cast to do here? Casting `opts` to uint8_t isn't going to change the allocated storage size. The only way to do that is to declare `opts` as `uint8_t` (or whatever) instead of `options_t`, like I said earlier. Using the packed attribute would affect the storage size of anything declared as `options_t`, but depends on the range of the enumerated values. The cast won't meaningfully affect the comparison unless opts is stored at >8 bits and has bits set beyond the low byte, in which case it may break the comparison (depending on what you're trying to achieve). Integer promotion rules will still apply as well. ARM for example has zero- and sign-extension and word/half-word/byte load and store instructions so when required the compiler can transform 8 bit values into 32 bit values and vice versa as part of a load/store with no penalty and it'll be atomic as long as they're aligned.