how to restrict enum conversions ?

Discussion in 'C Programming' started by O. Zimmermann, Nov 15, 2005.

  1. 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
    O. Zimmermann, Nov 15, 2005
    #1
    1. Advertising

  2. O. Zimmermann

    Eric Sosman Guest

    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.

    --
    Eric Sosman, Nov 15, 2005
    #2
    1. Advertising

  3. "O. Zimmermann" <2p3.fr> writes:
    > 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.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Nov 15, 2005
    #3
  4. O. Zimmermann wrote:
    > 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

    --
    I am the "ILOVEGNU" signature virus. Just copy me to your
    signature. This email was infected under the terms of the GNU
    General Public License.
    August Karlstrom, Nov 15, 2005
    #4
  5. O. Zimmermann

    Guest

    > 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);
    }
    , Nov 15, 2005
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. -

    enum within an enum

    -, Jun 12, 2005, in forum: Java
    Replies:
    6
    Views:
    538
  2. Jerminia
    Replies:
    3
    Views:
    623
    Roedy Green
    Oct 7, 2005
  3. Ernst Murnleitner

    How to enum an enum?

    Ernst Murnleitner, Nov 12, 2003, in forum: C++
    Replies:
    5
    Views:
    463
    Rolf Magnus
    Nov 13, 2003
  4. mrhicks
    Replies:
    2
    Views:
    417
    Dave Thompson
    Jun 10, 2004
  5. Replies:
    10
    Views:
    706
    Jasen Betts
    Aug 5, 2005
Loading...

Share This Page