EEVblog Electronics Community Forum

Electronics => Microcontrollers => Topic started by: ricko_uk on June 12, 2021, 12:02:49 am

Title: Forcing enum to be of a specific size
Post by: ricko_uk on June 12, 2021, 12:02:49 am
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 :)
Title: Re: Forcing enum to be of a specific size
Post by: ajb on June 12, 2021, 12:21:39 am
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.html

However 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.
Title: Re: Forcing enum to be of a specific size
Post by: SiliconWizard on June 12, 2021, 02:09:17 am
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.

Yes, 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.

Title: Re: Forcing enum to be of a specific size
Post by: ajb on June 12, 2021, 02:58:35 am
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.
Title: Re: Forcing enum to be of a specific size
Post by: Tagli on June 12, 2021, 05:00:03 am
In C++, you can choose the underlying type for both classical enums and enum classes.

Code: [Select]
enum class Number : uint8_t {Zero = 0, One = 1, Two = 2};
Title: Re: Forcing enum to be of a specific size
Post by: SiliconWizard on June 12, 2021, 04:49:33 pm
In C++, you can choose the underlying type for both classical enums and enum classes.

Code: [Select]
enum class Number : uint8_t {Zero = 0, One = 1, Two = 2};

I 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.
Title: Re: Forcing enum to be of a specific size
Post by: Tagli on June 12, 2021, 05:07:07 pm
It's available since C++11.
https://en.cppreference.com/w/cpp/language/enum
Title: Re: Forcing enum to be of a specific size
Post by: ricko_uk on June 12, 2021, 06:31:11 pm
Thank you all! :)

Title: Re: Forcing enum to be of a specific size
Post by: DavidAlfa on June 12, 2021, 08:59:48 pm
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: [Select]
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
Title: Re: Forcing enum to be of a specific size
Post by: ajb on June 12, 2021, 09:49:15 pm
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.