how to restrict enum conversions ?

O

O. Zimmermann

Hi all,

A variable with an enumerated type can be set with a value from any
other generic "enum" type in the program, or with an integer value,
without notice to the user, neither at compilation nor at execution.

How can I make this IMPOSSIBLE (so that ONLY a value from the expected
enumerated type can be fed to the variable, with no implicit
conversion allowed ?).

Is "typedef enum" the way to go ?


Thanks for your insights - oz
 
E

Eric Sosman

O. Zimmermann wrote On 11/15/05 10:58,:
Hi all,

A variable with an enumerated type can be set with a value from any
other generic "enum" type in the program, or with an integer value,
without notice to the user, neither at compilation nor at execution.

How can I make this IMPOSSIBLE (so that ONLY a value from the expected
enumerated type can be fed to the variable, with no implicit
conversion allowed ?).

Is "typedef enum" the way to go ?

No; an `enum xxx' type is just an ordinary integer
of a compiler-determined flavor, and the enumerated
names themselves are merely `int' constants.

Here's a hack inspired by Java that would solve
part of your problem:

typedef struct {
int value;
} Veggie;

const Veggie AVOCADO = { 1 };
const Veggie BANANA = { 2 };
...
const Veggie ZUCCHINI = { 26 };

typedef struct {
int value;
} Animal;

const Animal AARDVARK = { 1 };
const Animal BEAR = { 2 };
...
const Animal ZEBRA = { 26 };

This will allow `Veggie v1 = AVOCADO', for example,
but `Veggie v2 = AARDVARK' will provoke a compile-time
diagnostic.

It's not perfect, though. You can't prevent someone
from writing `Veggie v3 = { -42 }', for example. Also,
you give up the ability to use AVOCADO et al. as case
labels, or to compare `v3 == ZUCCHINI'. It's up to you
to decide whether the drawbacks of the scheme are more
or less painful than trying to police the use of enums.
 
K

Keith Thompson

O. Zimmermann said:
A variable with an enumerated type can be set with a value from any
other generic "enum" type in the program, or with an integer value,
without notice to the user, neither at compilation nor at execution.

How can I make this IMPOSSIBLE (so that ONLY a value from the expected
enumerated type can be fed to the variable, with no implicit
conversion allowed ?).

Is "typedef enum" the way to go ?

Basically, you can't (other than by using a different language).
Enumeration types are really nothing more than thinly veiled integers.
Typedef won't help; it just creates an alias for an existing type, not
a new type.

There are ways to do similar things (Eric Sosman posted some ideas),
but they have drawbacks.

C generally has weak type checking -- or, more precisely, it provides
implicit conversions in a lot of cases. As Eric points out, there are
no such implicit conversions for struct types.
 
A

August Karlstrom

O. Zimmermann said:
A variable with an enumerated type can be set with a value from any
other generic "enum" type in the program, or with an integer value,
without notice to the user, neither at compilation nor at execution.

How can I make this IMPOSSIBLE (so that ONLY a value from the expected
enumerated type can be fed to the variable, with no implicit conversion
allowed ?).

I don't think you can. Switch to a language which focus on safety.


August
 
P

plunket

How can I make this IMPOSSIBLE (so that ONLY a value from the expected
enumerated type can be fed to the variable, with no implicit
conversion allowed ?).

"Impossible" is a strong word.

However, if you want to "play nice" and restrict yourself to an API
(which has hopefully-obvious paths for release-build optimizations if
desired), do something like I demonstrate below. This can become
considerably easier if you don't allow "holes" in the values you
operate on, and easier yet again if you always start at zero (e.g.
don't provide MY_ENUM_VAL).

The way this is split between headers and implementation files is left
to the reader. The key here is that the list of enum names is only
defined in one list. Duplication being the root of all evil and all
that...

I have used a system much like this for file reading and writing, where
the code that read and wrote enums used the symbolic version of the
enum value, so config files would be more readily readable by the end
user.

#define MY_ENUM_LIST \
MY_ENUM(Apple) \
MY_ENUM(Banana) \
MY_ENUM_VAL(Avocado, 26)

#define MY_ENUM(x) x,
#define MY_ENUM_VAL(x, y) x = y,

typedef enum _Fruit
{
MY_ENUM_LIST
} Fruit;

#undef MY_ENUM
#undef MY_ENUM_VAL

#define MY_ENUM(x) x,
#define MY_ENUM_VAL(x, y) x,

Fruit g_allowedFruit[] = { MY_ENUM_LIST };
int g_numAllowedFruits = sizeof(g_allowedFruit) /
sizeof(g_allowedFruit[0]);

#undef MY_ENUM
#undef MY_ENUM_VAL

int FindFruit(Fruit f)
{
/* Binary search the allowed list, and return the correct index.
Return -1 on error */
}

Fruit NextEnum(Fruit f)
{
int index = FindFruit(f)
index++;
if (index < g_numAllowedFruits)
return g_allowedFruit[index];
else
ItsAnError();
}

Fruit PreviousEnum(Fruit f)
{
int index = FindFruit(f)
index--;
if (index >= 0)
return g_allowedFruit[index];
else
ItsAnError();
}

int ValidateEnum(Fruit f)
{
return (FindFruit(f) >= 0);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top