tags:

views:

102

answers:

4

The following is a typical situation in our codebase.

enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 }

ConfigOption cfg1, cfg2;

sscanf(s, "%d", &cfg1);

This is an internally used simulation software. Not distributed. Ease of maintenance and correctness are important. Portability and user interface -- not really.

The trouble is enum in C++ is not necessarily an int. So we get a compiler warning, and may get incorrect behavior when using a different compiler or when optimizations are enabled.

One solution is just to cast &cfg to int*. However this will not catch cases where the compiler had decided to allocate something other than int to the enum.

So I suggested the following solution:

template<typename T> inline
int& eint(T& enum_var) {
    assert(sizeof(T) == sizeof(int));
    return (int&)enum_var;
}

And now one uses scanf as follows:

sscanf(s, "%d", &eint(cfg1));

I would love to hear opinions and other (better) solutions to the above problem. Keep in mind that one of the goals is to keep the code simple. This is not 'production-quality' stuff and the more you add -- the more difficult maintenance becomes.

A: 

You could try using boost::lexical_cast, or if you aren't using boost and don't want to start using it for just this case, you could just write a simplified version of that yourself. For an example take a look at this SO answer.

Dmitry
`boost::lexical_cast` relies on stream operator `<<` and `>>` overloads. It would work with an enum only if those operators are overloaded for this enum.
UncleBens
+2  A: 

My solution would be to force the enum to a minimum size.. That's what Microsoft did for their enums in their DirectX headerfiles (a nice trick I have to admit).

They enforced the size of the enum to be equal to an int by adding a dummy enum like this:

typedef enum 
{
  fooo = 1,
  baar = 2,
  ___Force32Bit = ~0UL
} MyEnum;

Now the enum will always be at least the size of an int.

If you want to you can take this over the top.. This one forces the size of the enum to a long long:

typedef enum 
{
  fooo = 1,
  baar = 2,
  ___Force64Bit = ~0ULL
} MyEnum;

I know, it is not a super clean solution. I think such a solution does not exist and enforcing a minimum size worked well for me so far. You may have to adjust the code if you go from 32 to 64 bit code, but usually in these situations you have to review some parts of the code anyway, so no big issue.

Btw - sorry for the C-code, I know the question was tagged as C++, but I'm a C-guys :-)

Nils Pipenbrinck
+2  A: 

If you have a modern compiler like vs2010 you can specify the size of the enum elements

enum class ConfigOption: unsigned int {CONFIG_1=1, CONFIG_2=2, CONFIG_3=3};

its new in C++0x

Anders K.
cool! Nice feature.
Nils Pipenbrinck
Unfortunately we still use an old version of gcc. Still, this seems the cleanest solution, so I'll accept it.
nimrodm
+1  A: 

Why not just read it as an actual int?

enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 };
ConfigOption cfg1;

int i;
sscanf(s, "%d", &i);
cfg1 = i;

And that way you can do more comprehensive validity checks too (such as testing that the read integer is within the range of your enum type).

(Of course, if you're at all concerned about detecting errors, for simple parsing like this, you should be using strtol or strtoul instead of sscanf.)

jamesdlin
Correct, but annoying (and you still need a cast for the assigment). We have tons of these...
nimrodm