On 10/09/2012 04:58 AM, David Turner wrote:
> The enum is a little trickier. AFAIK an enum type is always internally 
> a uint16 (short int) or uint32 (int) type, which will double or 
> quadruple the const memory usage in the compiled binary compared to 
> the uint8 (byte) type, though I wasn't sure whether the effect of 
> alignment / masking on access would actually prevent any saving in 
> real-world usage.
>
> The issue I was trying to avoid was increasing the ROM (code segment) 
> usage in the ScummVM teenagent engine as a side-effect of doing the 
> refactoring and adding readable symbols. If I had used defines, then 
> any symbol used multiple times would probably still be multiple values 
> in the const segment, so doing this as a const variable should 
> "deduplicate" and thus save ROM. enums would be better, but their size 
> is the issue.
>
> I should explain that saving an extra byte here and there is not 
> normally a critical aim, except that the Teenagent engine open bugs 
> are mainly reported from PSP and other memory-limited platforms and a 
> secondary aim of the refactoring was to close memory leaks and reduce 
> RAM usage, but without significant increase in ROM usage.
>
> I'm also not sure if I tried making this int/enum and I found it 
> required casts on usage to prevent "precision loss" type compiler 
> wanrings...
>
> Does fuzzie or anyone familar with detail of compiler internals know 
> if an enum type is dynamically sized to save memory , if it can be 
> type selected or if it is fixed at uint32 (int)?
>
> P.S. I may be "overthinking" this and the actual saving is neglible, 
> but I made this choice a while back and I can't quite remember the 
> rationale at the time.
>

Yes, that sounds like you are "overthinking" this. Both the enum and 
your constants should result in a "inlined" usage of the values. Also a 
(good) compiler should try to use the smallest available instruction to 
load immediate data into registers (or for comparison, that all depends 
on what instructions your target architecture has...), so even if you 
have constant int with value 5 it should rather load a immediate 5 
(should be 16 bits on MIPS IIRC and thus fit in a immediate instruction) 
than a full 32 bit 5 (which would be two instructions IIRC). That's the 
basic idea at least.

The gcc used for PSP on our buildbot produces the same object code for 
this example:

```
#ifdef ENUM
enum {
         kFoo = 20
};
#else
const unsigned char kFoo = 20;
#endif

int main(int argc, char *argv[]) {
#if 0
         // will also result in the same code
         return argc == kFoo;
#else
         unsigned char byte = *(argv[4]);
         return byte == kFoo;
#endif
}
```

C++98 enums don't really have any specific type, the implementation can 
choose a type which fits all the values in the enumeration. You also 
can't specify the underlying type by yourself.

I can't make any sense of the alignment etc. reasons you come up with 
though.

PS: Here's a quote from the C++98 standard:

 > The underlying type of an enumeration is an integral type that can 
represent all the enumerator values
 > defined in the enumeration. It is implementation-defined which 
integral type is used as the underlying type
 > for an enumeration except that the underlying type shall not be 
larger than int unless the value of an enu-
 > merator cannot fit in an int or unsigned int.