How to make a enum with values over max int allowed?

10

I'm making a enum in c++ to make a finite state machine using binary flags. It looks like:

enum VStates
{
    NEUTRAL         =   0x00000000,     // 000000
    //  Physical Status
    DRY             =   0x00000001,     // 000001
    WET             =   0x00000002,     // 000010
    HOT             =   0x00000004,     // 000100
    COLD            =   0x00000008,     // 001000
    BURNED          =   0x00000016,     // etc..
    FROZEN          =   0x00000032,
    EROS            =   0x00000064,     // 
    THANATOS        =   0x00000128,     // 
    SLEEP           =   0x00000256,
    STUNNED         =   0x00000512,
    PARALYZED       =   0x00001024,
    POISONED        =   0x00002048,     //
    BLIND           =   0x00004096,
    SOFT            =   0x00008192,     // Flexible
    TOUGH           =   0x00016384,     // Resistent
    MAGNETIZED      =   0x00032768,
    POSSEDERUNT     =   0x00131072,     //
    // Mental Status
    ANGRY           =   0x00262144,
    DRUGGED         =   0x00524288, // Drugs Meaning
    HORNY           =   0x01048576, // Sexual Meaning
    // Material Status
    METAL           =   0x02097152,
    WOOD            =   0x04194304,
    GLASS           =   0x08388608,
    AIR             =   0x16777216,
    EARTH           =   0x33554432,
    DUST            =   0x67108864,
    LIGHT           =   0x134217728,
    SHADOW          =   0x268435456,
    WATER           =   0x536870912,
    // Total Status
    PROTECTED       =   0x1073741824,
    INVULNERABLE    =   0x2147483648

};

Some status are incompatibles, so I use Bitwise operators to manage them. Now, my compiler say:

warning: integer constant is too large for 'long' type

Is this the correct way to declare this enum? I like avoid warning so, How can I resolve this problem?

c++
variables
enums
asked on Stack Overflow Nov 14, 2012 by vgonisanz

5 Answers

13

In C++11, you can specify the underlying type of the enum.

#include <cstdint>

enum VStates : uint64_t {
    // Values
}

On a side note, I recommend against calculating out all of those powers of two. You made an error in your calculations by writing a hex constant but giving it the digits of a base-10 numeral. However, rather than recalculating all of those, I recommend something like:

#include <cstdint>

enum VStates : uint64_t {
    NEUTRAL = 0ULL,
    DRY = 1ULL << 0,
    WET = 1ULL << 1,
    HOT = 1ULL << 2,
    COLD = 1ULL << 3,
    // etc.
}

Then you are sure not to make a mistake. The ULL suffix ensures that the literal is accepted as at least a 64-bit wide integer.

answered on Stack Overflow Nov 14, 2012 by David Stone
11

(Note: to make my answer complete I'll add in something I didn't take time to notice but others have pointed out: you're using the 0x prefix, which means your numbers would be interpreted as hexadecimal. They'd not actually be powers of two, and your bitflag tests would not have worked!)

If your enumerations are running out of control like this, don't use an enumerated type. Use something like a std::bitset. Then your enum can just be a simple numbered list of names for the positions of the bits in the set...and you won't be exhausting your enumeration space exponentially!

For example:

enum VState {
    NEUTRAL,
    DRY,
    WET,
    COLD,
    BURNED,
    FROZEN,
    /* ... */
    VState_Max
};

bitset<VState_Max> state;

state[COLD] = true;
if (state[COLD]) {
    cout << "I am cold\n";
}

Now your enum is just small, maintainable numbers and you don't have to worry about being on a 64-bit platform or whatnot.

I note that you gave a value of "0" for NEUTRAL in your original example. If your intent was to have it be possible to use this in combination with other things...such as being able to be state = NEUTRAL | INVULNERABLE | SHADOW and individually test for NEUTRAL, that wouldn't have worked before. It will now...you'd just keep it in the enumeration for indexing the bitset.

But if it intended as a name for "nothing set", then you would remove it from the enum and instead test for no bits set with:

if (state.none()) {
    // we are in the "NEUTRAL" state of nothing set...
}

...and if you wanted to set all the bits to false, you'd go with:

state.reset();
4

The enumeration has 31 non-zero values, so they can all fit in a 32-bit unsigned value. The problem is that the values here aren't bit-values. Either write them as decimal values (remove the 0x from the front) or write them as hexadecimal values (0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, etc.) I personally don't like it, but some people write this kind of constant with shifts: 1<<0, 1<<1, 1<<2, 1<<3, etc.

answered on Stack Overflow Nov 14, 2012 by Pete Becker
3

If you are using C++11, you can declare a strongly-typed enum with a defined type as unsigned long long (_int64 in Windows, though you should probably use the portable uint64_t), if that extends your range far enough.

Thanks to Joachim for a link to examples of C++11 enum usage: Strongly Typed Enums

answered on Stack Overflow Nov 14, 2012 by im so confused
0

Use smaller numbers. An enum can only be as big as a long. The size of a long depends on the compiler, but a typical size is either 32 or 64 bits. I see some 10 digit hex numbers there, those are too big.

answered on Stack Overflow Nov 14, 2012 by Gabe Sechan

User contributions licensed under CC BY-SA 3.0