enum safety

Discussion in 'C Programming' started by Sard, Feb 8, 2008.

  1. Sard

    Sard Guest

    Hi,

    Page 39 K&R2 says

    'Although variables of enum types may be declared, compilers need not
    check that what you store in such a variable is a valid value for the
    enumeration'

    gcc produces an error for the code below as I'm trying to assign a
    pointer to char to the a variable of type colour. Is gcc going beyond
    the call of duty? Why would the standard allow compilers to accept
    such code?

    #include <stdio.h>
    #include <limits.h>

    char* c=0;

    enum colours {
    Red,Blue

    };


    int main ()
    {
    enum colours purple =c ;

    return 0;
    }
    Sard, Feb 8, 2008
    #1
    1. Advertising

  2. Sard

    Guest

    On Feb 8, 11:22 am, Sard <> wrote:
    > Hi,
    >
    > Page 39 K&R2 says
    >
    > 'Although variables of enum types may be declared, compilers need not
    > check that what you store in such a variable is a valid value for the
    > enumeration'
    >
    > gcc produces an error for the code below as I'm trying to assign a
    > pointer to char to the a variable of type colour.  Is gcc going beyond
    > the call of duty?  Why would the standard allow compilers to accept
    > such code?
    >
    > #include <stdio.h>
    > #include <limits.h>
    >
    > char* c=0;
    >
    > enum colours {
    > Red,Blue
    >
    > };
    >
    > int main ()
    > {
    >  enum colours purple =c ;
    >
    >   return 0;
    >
    >
    >
    > }- Hide quoted text -
    >
    > - Show quoted text -


    c is a pointer, not an integer.
    It is not assignable to purple without a cast.
    --
    Fred Kleinschmidt
    , Feb 8, 2008
    #2
    1. Advertising

  3. Sard

    Ian Collins Guest

    Sard wrote:
    > Hi,
    >
    > Page 39 K&R2 says
    >
    > 'Although variables of enum types may be declared, compilers need not
    > check that what you store in such a variable is a valid value for the
    > enumeration'
    >

    This is why (in my opinion) enums are horribly broken in C.

    > int main ()
    > {
    > enum colours purple =c ;
    >

    c is a pointer, enums are integer types.

    You would get the same diagnostic with

    int n = c;

    --
    Ian Collins.
    Ian Collins, Feb 8, 2008
    #3
  4. Sard <> writes:
    > Page 39 K&R2 says
    >
    > 'Although variables of enum types may be declared, compilers need not
    > check that what you store in such a variable is a valid value for the
    > enumeration'


    Right. In fact, the above statement is too weak; compilers aren't
    even allowed to perform such checks (or at least they're not allowed
    to reject the program if such a check fails).

    > gcc produces an error for the code below as I'm trying to assign a
    > pointer to char to the a variable of type colour. Is gcc going beyond
    > the call of duty? Why would the standard allow compilers to accept
    > such code?
    >
    > #include <stdio.h>
    > #include <limits.h>
    >
    > char* c=0;
    >
    > enum colours {
    > Red,Blue
    >
    > };
    >
    >
    > int main ()
    > {
    > enum colours purple =c ;
    >
    > return 0;
    > }


    The compiler needn't check for a valid value. It must check for a
    valid type. In this case, c is of type char*, purple is of type enum
    colours, and there's no implicit conversion. This really has nothing
    to do with it being an enum type.

    What K&R is talking about is something like this:

    #include <stdio.h>
    int main(void)
    {
    enum colors { red = 10, blue = 20 };
    enum colors purple = 15;
    printf("purple = %d\n", (int)purple);
    return 0;
    }

    This is perfectly legal; a particularly picky compiler might warn
    about it, but it must accept it and it must produce the output
    purple = 15

    An enum type declaration really does two things. It creates an
    enumerated type (which must be compatible with some existing integer
    type and must be able to hold all the specified values), and it
    creates a series of constants (which, oddly enough, are of type int,
    not of the enumerated type). It looks a lot like the enumerated types
    you might see in other languages such as Pascal, and you can use it
    for the same purposes if you're careful, but it's really quite
    different.

    Note that this provides a cute mechanism for creating a named constant
    of type int:

    enum { MAX=1000 };

    The type is anonymous and is never used; MAX is a constant of type int
    with the value 1000. This is arguably cleaner than a macro, but it
    doesn't extend to types other than int.

    --
    Keith Thompson (The_Other_Keith) <>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Feb 8, 2008
    #4
  5. Sard

    Eric Sosman Guest

    Keith Thompson wrote:
    > [...]
    > What K&R is talking about is something like this:
    >
    > #include <stdio.h>
    > int main(void)
    > {
    > enum colors { red = 10, blue = 20 };
    > enum colors purple = 15;
    > printf("purple = %d\n", (int)purple);
    > return 0;
    > }
    >
    > This is perfectly legal; a particularly picky compiler might warn
    > about it, but it must accept it and it must produce the output
    > purple = 15


    Another (and perhaps more plausible) use of non-enumerated
    enum values is in constructing sets of flags by OR-ing named
    values together:

    enum {
    PRESENT = 0x1, CORRECT = 0x2, SALUTING = 0x4
    } status;
    status = PRESENT | CORRECT;
    puts ("All present and correct, sir!");
    receive_stern_look(from_officer);
    status |= SALUTING;
    puts ("Aye, aye, sir!");

    --
    Eric Sosman
    lid
    Eric Sosman, Feb 8, 2008
    #5
  6. Sard

    Army1987 Guest

    Ian Collins wrote:

    > Sard wrote:
    >> Hi,
    >>
    >> Page 39 K&R2 says
    >>
    >> 'Although variables of enum types may be declared, compilers need not
    >> check that what you store in such a variable is a valid value for the
    >> enumeration'
    >>

    > This is why (in my opinion) enums are horribly broken in C.

    Not necessarily. For example, you can have an object which can contain
    a number up to 10 as numbers, and 11, 12 and 13 with special meanings. E.g.
    enum rank { ACE = 1, JACK = 11, QUEEN = 12, KING = 13 };
    enum rank foo = 7;
    (For example mbrtowc can return a number of bytes, or 0, (size_t)(-2) and
    (size_t)(-1) with special meanings. Here an enum won't do it because
    constants must fit in an int, but one might have an int-returning function
    with similar semantics. Maybe using negative numbers:
    enum err_code { OUT_OF_MEMORY = -2, IO_ERROR = -1, MAX = INT_MAX };

    --
    Army1987 (Replace "NOSPAM" with "email")
    Army1987, Feb 9, 2008
    #6
  7. Sard

    Ian Collins Guest

    Army1987 wrote:
    > Ian Collins wrote:
    >
    >> Sard wrote:
    >>> Hi,
    >>>
    >>> Page 39 K&R2 says
    >>>
    >>> 'Although variables of enum types may be declared, compilers need not
    >>> check that what you store in such a variable is a valid value for the
    >>> enumeration'
    >>>

    >> This is why (in my opinion) enums are horribly broken in C.

    > Not necessarily. For example, you can have an object which can contain
    > a number up to 10 as numbers, and 11, 12 and 13 with special meanings. E.g.
    > enum rank { ACE = 1, JACK = 11, QUEEN = 12, KING = 13 };
    > enum rank foo = 7;


    That illustrates the problem perfectly, you declare declare a valid
    range of values for rank and then legally assign some other arbitrary
    value to it. Useless.

    --
    Ian Collins.
    Ian Collins, Feb 9, 2008
    #7
  8. Sard

    Anonymous Guest

    On Sun, 10 Feb 2008 08:32:45 +1300, Ian Collins wrote:

    > That illustrates the problem perfectly, you declare declare a valid
    > range of values for rank and then legally assign some other arbitrary
    > value to it. Useless.


    enum SomeFlags {
    FLAG_NONE = 0,
    FLAG_FROB = 1 << 0,
    FLAG_BARF = 1 << 1,
    FLAG_FISH = 1 << 2,
    };

    enum SomeFlags = FLAG_FROB | FLAG_FISH;

    Aribitrary value assigned. Still useful.
    Anonymous, Feb 9, 2008
    #8
  9. Ian Collins <> writes:
    > Army1987 wrote:
    >> Ian Collins wrote:
    >>> Sard wrote:
    >>>> Page 39 K&R2 says
    >>>>
    >>>> 'Although variables of enum types may be declared, compilers need not
    >>>> check that what you store in such a variable is a valid value for the
    >>>> enumeration'
    >>>>
    >>> This is why (in my opinion) enums are horribly broken in C.

    >> Not necessarily. For example, you can have an object which can contain
    >> a number up to 10 as numbers, and 11, 12 and 13 with special meanings. E.g.
    >> enum rank { ACE = 1, JACK = 11, QUEEN = 12, KING = 13 };
    >> enum rank foo = 7;

    >
    > That illustrates the problem perfectly, you declare declare a valid
    > range of values for rank and then legally assign some other arbitrary
    > value to it. Useless.


    It seems perfectly useful to me. An object of type enum range can
    sensibly hold any value from 1 to 13. The values 1, 11, 12, and 13
    happen to have names associated with them; the others are merely
    numbers. The language guarantees that this will work (in fact, it
    guarantees that values in the range 0..127 are valid).

    A C enumerated type doesn't act like an enumerated type in, say,
    Pascal or Ada, but it's not supposed to. It merely provides a set of
    names for specific values, and an integral type that can hold all
    those values.

    --
    Keith Thompson (The_Other_Keith) <>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Feb 10, 2008
    #9
  10. "Anonymous" <> schreef in bericht
    news:7Oorj.8725$...
    > On Sun, 10 Feb 2008 08:32:45 +1300, Ian Collins wrote:
    >
    >> That illustrates the problem perfectly, you declare declare a valid
    >> range of values for rank and then legally assign some other arbitrary
    >> value to it. Useless.

    >
    > enum SomeFlags {
    > FLAG_NONE = 0,
    > FLAG_FROB = 1 << 0,
    > FLAG_BARF = 1 << 1,
    > FLAG_FISH = 1 << 2,
    > };
    >
    > enum SomeFlags = FLAG_FROB | FLAG_FISH;
    >
    > Aribitrary value assigned. Still useful.


    Not really, using an enum here is useless. In fact, in some coding standard
    (misra I think) its forbidden to use enums in this way. I dont want to argue
    about that ruke, but it does show there are other ways in C to accomplish
    this and not by abusing enum
    Serve Laurijssen, Feb 10, 2008
    #10
  11. Sard

    Eric Sosman Guest

    Serve Laurijssen wrote:
    >
    > "Anonymous" <> schreef in bericht
    > news:7Oorj.8725$...
    >> On Sun, 10 Feb 2008 08:32:45 +1300, Ian Collins wrote:
    >>
    >>> That illustrates the problem perfectly, you declare declare a valid
    >>> range of values for rank and then legally assign some other arbitrary
    >>> value to it. Useless.

    >>
    >> enum SomeFlags {
    >> FLAG_NONE = 0,
    >> FLAG_FROB = 1 << 0,
    >> FLAG_BARF = 1 << 1,
    >> FLAG_FISH = 1 << 2,
    >> };
    >>
    >> enum SomeFlags = FLAG_FROB | FLAG_FISH;


    Missing an identifier here ...

    >> Aribitrary value assigned. Still useful.

    >
    > Not really, using an enum here is useless. In fact, in some coding
    > standard (misra I think) its forbidden to use enums in this way. I dont
    > want to argue about that ruke, but it does show there are other ways in
    > C to accomplish this and not by abusing enum


    (Shrug.) The alternative would be something like

    typedef unsigned int Flagset;
    #define FLAG_NONE 0
    #define FLAG_FROB (1 << 0)
    #define FLAG_BARF (1 << 1)
    #define FLAG_FISH (1 << 2)
    Flagset kirsten = FLAG_FROB | FLAG_FISH;

    .... which seems a pretty close equivalent. In particular, it
    is neither more nor less risky than using an enum.

    --
    Eric Sosman
    lid
    Eric Sosman, Feb 10, 2008
    #11
  12. Sard

    Ian Collins Guest

    Keith Thompson wrote:
    > Ian Collins <> writes:
    >> Army1987 wrote:
    >>> Ian Collins wrote:
    >>>> Sard wrote:
    >>>>> Page 39 K&R2 says
    >>>>>
    >>>>> 'Although variables of enum types may be declared, compilers need not
    >>>>> check that what you store in such a variable is a valid value for the
    >>>>> enumeration'
    >>>>>
    >>>> This is why (in my opinion) enums are horribly broken in C.
    >>> Not necessarily. For example, you can have an object which can contain
    >>> a number up to 10 as numbers, and 11, 12 and 13 with special meanings. E.g.
    >>> enum rank { ACE = 1, JACK = 11, QUEEN = 12, KING = 13 };
    >>> enum rank foo = 7;

    >> That illustrates the problem perfectly, you declare declare a valid
    >> range of values for rank and then legally assign some other arbitrary
    >> value to it. Useless.

    >
    > It seems perfectly useful to me. An object of type enum range can
    > sensibly hold any value from 1 to 13. The values 1, 11, 12, and 13
    > happen to have names associated with them; the others are merely
    > numbers. The language guarantees that this will work (in fact, it
    > guarantees that values in the range 0..127 are valid).
    >
    > A C enumerated type doesn't act like an enumerated type in, say,
    > Pascal or Ada, but it's not supposed to. It merely provides a set of
    > names for specific values, and an integral type that can hold all
    > those values.
    >

    Or in C++, where they are first class types. A C enum is little
    different from a typedef and a set of #defines. It's the lack of type
    safety I don't like. Maybe it as was a bad experience with come code
    that tried to use enems as types, but ended up abusing them (assigning
    wrong values) that made me feel this way.

    --
    Ian Collins.
    Ian Collins, Feb 10, 2008
    #12
  13. Ian Collins <> writes:
    > Keith Thompson wrote:

    [...]
    >> A C enumerated type doesn't act like an enumerated type in, say,
    >> Pascal or Ada, but it's not supposed to. It merely provides a set of
    >> names for specific values, and an integral type that can hold all
    >> those values.
    >>

    > Or in C++, where they are first class types. A C enum is little
    > different from a typedef and a set of #defines.


    Exactly (except that the names of the constants follow the scoping
    rules of ordinary identifiers rather than of macros, which IMHO is a
    considerable advantage).

    > It's the lack of type
    > safety I don't like.


    Welcome to C! :cool:}

    > Maybe it as was a bad experience with come code
    > that tried to use enems as types, but ended up abusing them (assigning
    > wrong values) that made me feel this way.


    A C enumerated type is what it is. No more, no less. As long as you
    keep that in mind, and *don't* confuse it with similar features in
    other languages, they're not that hard to use.

    You can have an enumerated type for which only the named values are
    considered valid. Assigning some other value is then a logical bug in
    your program, one that the compiler unfortunately won't help you
    detect (unless you write your own range-checking code). But nothing
    else in C will detect this kind of logical error either (unless you
    write your own range-checking code). What the "enum" construct gives
    you is a convenient way for the compiler to assign consecutive values
    to your constants, and to choose a type that can hold all of them.

    Or you can have an enumerated type where only some of the valid values
    have names assigned to them, and assigning some other value is not an
    error:
    enum card_rank { ace = 1, jack = 11, queen = 12, king = 13 };

    Or you can have an anonymous enumerated type if all you're interested
    in is the constants:
    enum { MAX_LENGTH = 256 };

    It might have made more sense to have three different language
    constructs for these three things. But if we were going to insist on
    everything making sense, we probably wouldn't be using C.

    --
    Keith Thompson (The_Other_Keith) <>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Feb 10, 2008
    #13
    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:
    533
  2. Jerminia
    Replies:
    3
    Views:
    622
    Roedy Green
    Oct 7, 2005
  3. Ernst Murnleitner

    How to enum an enum?

    Ernst Murnleitner, Nov 12, 2003, in forum: C++
    Replies:
    5
    Views:
    456
    Rolf Magnus
    Nov 13, 2003
  4. mrhicks
    Replies:
    2
    Views:
    414
    Dave Thompson
    Jun 10, 2004
  5. Randy
    Replies:
    1
    Views:
    516
    David Harmon
    Jan 7, 2006
Loading...

Share This Page