Enums without identifier, enums and typedef

Discussion in 'C Programming' started by =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=, Jan 19, 2007.

  1. I came over this code which puzzled me. Isn't the enum supposed to
    have an identifier?

    enum {
    BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
    BT_OPEN,
    BT_BOUND,
    BT_LISTEN,
    BT_CONNECT,
    BT_CONNECT2,
    BT_CONFIG,
    BT_DISCONN,
    BT_CLOSED
    };


    Following this, I played around a bit, and came up with the program
    below, which I had hoped would provoke the compiler into issuing a
    warning about type mismatch (or something along those lines). Which
    it didn't. (gcc -std=c99 -Wall -pedantic).

    Care to comment?

    With kind regards
    Asbjørn Sæbø


    #include <stdio.h>

    typedef enum
    {
    M_A = 1,
    M_B,
    M_C,
    M_D
    } M_type;


    typedef enum
    {
    N_A = 1,
    N_B,
    N_C,
    N_D
    } N_type;


    void myfunc(M_type myvar)
    {
    printf("Inside myfunc, myvar is %d\n", myvar);
    }


    int main(void)
    {
    N_type a = N_B;

    myfunc(a); /* Feed variable of N_type into function expecting M_type */
    return 0;
    }
    =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=, Jan 19, 2007
    #1
    1. Advertising

  2. =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=

    Richard Bos Guest

    =?utf-8?b?QXNiasO4cm4gU8OmYsO4?= <> wrote:

    > I came over this code which puzzled me. Isn't the enum supposed to
    > have an identifier?


    Not necessarily.

    > enum {
    > BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
    > BT_OPEN,
    > BT_BOUND,
    > BT_LISTEN,
    > BT_CONNECT,
    > BT_CONNECT2,
    > BT_CONFIG,
    > BT_DISCONN,
    > BT_CLOSED
    > };


    This doesn't define a type, but it does define a number of constants.
    This can on occasion be quite useful. It is, for example, easier to
    maintain than a series of #defines.

    Richard
    Richard Bos, Jan 19, 2007
    #2
    1. Advertising

  3. =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=

    Guest

    Asbjørn Sæbø wrote:
    > I came over this code which puzzled me. Isn't the enum supposed to
    > have an identifier?
    >
    > enum {
    > BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
    > BT_OPEN,
    > BT_BOUND,
    > BT_LISTEN,
    > BT_CONNECT,
    > BT_CONNECT2,
    > BT_CONFIG,
    > BT_DISCONN,
    > BT_CLOSED
    > };


    Does the FAQ entry <http://c-faq.com/struct/enumvsdefine.html> help?

    Basically, I think it boils down to this - enums are for historical
    reasons, rather weakly specified. So in effect, you are just creating
    some integral constants here. Likewise in your example program, because
    of the weak specification values from one enum can be used where
    another is specified - enum types are "just" some integer type.
    , Jan 19, 2007
    #3
  4. writes:

    > [...]
    > Does the FAQ entry <http://c-faq.com/struct/enumvsdefine.html> help?


    Yes. Although this probably means that the practice I have seen of
    typedef-ings enums does not help much when it comes to catching
    errors.

    Thanks, both to you and Richard Bos.

    Asbjørn S.
    =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=, Jan 19, 2007
    #4
  5. "Asbjørn Sæbø" <> wrote in message
    news:...
    >
    > I came over this code which puzzled me. Isn't the enum supposed to
    > have an identifier?
    >
    > enum {
    > BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
    > BT_OPEN,
    > BT_BOUND,
    > BT_LISTEN,
    > BT_CONNECT,
    > BT_CONNECT2,
    > BT_CONFIG,
    > BT_DISCONN,
    > BT_CLOSED
    > };


    Looks fine to me.

    I don't know the standards -- I just have years of messing around with
    compilers.

    Based on years of messing around and randomly modifying code until it seems
    to work most of the time ... an enum is generally interchangeable with an
    integer, and the compiler won't enforce type. Passing an integer where an
    enum is "expected" or passing an enumerated constant where an integer is
    expected seems to generate no warnings or errors.

    I don't know the standards, but the code excerpt above behaves about the
    same as:

    #define BT_CONNECTED (1)
    #define BT_OPEN (2)
    etc.

    The only advantage to enums seems to be that they allow the compiler to
    number the constants itself. In fact, in the example you gave, my code
    would also traditionally include a symbol like "BT_MAX" at the end to test
    for a corrupted or unexpected variable (and of course, the value of BT_MAX
    will be modified if constants are added or removed earlier in the list).

    Enums in C are treated oddly--the typing is very weak. The automatic
    numbering of the constants is the only aspect of it I've found useful.

    --
    David T. Ashley ()
    http://www.e3ft.com (Consulting Home Page)
    http://www.dtashley.com (Personal Home Page)
    http://gpl.e3ft.com (GPL Publications and Projects)
    David T. Ashley, Jan 19, 2007
    #5
  6. Asbjørn Sæbø <> writes:
    > I came over this code which puzzled me. Isn't the enum supposed to
    > have an identifier?
    >
    > enum {
    > BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
    > BT_OPEN,
    > BT_BOUND,
    > BT_LISTEN,
    > BT_CONNECT,
    > BT_CONNECT2,
    > BT_CONFIG,
    > BT_DISCONN,
    > BT_CLOSED
    > };


    Perfectly legal. The tag on an enum type declaration is optional.
    The declaration creates a type (an anonymous one in this case),
    but the constants BT_CONNECTED et al are actually of type int.

    For the above declaration, the creation of the type (which can't be
    used anyway) is a side effect; the purpose of the declaration is to
    declare the constants. It's a cleaner alternatve to

    #define BT_CONNECTED 1
    #define BT_OPEN 2
    ...

    > Following this, I played around a bit, and came up with the program
    > below, which I had hoped would provoke the compiler into issuing a
    > warning about type mismatch (or something along those lines). Which
    > it didn't. (gcc -std=c99 -Wall -pedantic).


    [...]

    >
    > #include <stdio.h>
    >
    > typedef enum
    > {
    > M_A = 1,
    > M_B,
    > M_C,
    > M_D
    > } M_type;
    >
    >
    > typedef enum
    > {
    > N_A = 1,
    > N_B,
    > N_C,
    > N_D
    > } N_type;
    >
    >
    > void myfunc(M_type myvar)
    > {
    > printf("Inside myfunc, myvar is %d\n", myvar);
    > }
    >
    >
    > int main(void)
    > {
    > N_type a = N_B;
    >
    > myfunc(a); /* Feed variable of N_type into function expecting M_type */
    > return 0;
    > }


    There's no problem with the code. Values of enum or integer types may
    be implicitly converted back and forth.

    It would have been nice, in some ways, if the rules for enumerated
    types were more strict (as they are in some other languages), but
    they're not.

    --
    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, Jan 19, 2007
    #6
  7. =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=

    Ben Pfaff Guest

    Asbjørn Sæbø <> writes:

    > enum {
    > BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */


    Putting this in a comment is perverse. I would write this as:
    BT_CONNECTED = TCP_ESTABLISHED,
    and then there's no need for the comment at all.

    > BT_OPEN,
    > BT_BOUND,
    > BT_LISTEN,
    > BT_CONNECT,
    > BT_CONNECT2,
    > BT_CONFIG,
    > BT_DISCONN,
    > BT_CLOSED
    > };


    --
    int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.\
    \n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
    );while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p\
    );}return 0;}
    Ben Pfaff, Jan 19, 2007
    #7
  8. In article <>,
    Ben Pfaff <> wrote:

    >> enum {
    >> BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */

    >
    >Putting this in a comment is perverse. I would write this as:
    > BT_CONNECTED = TCP_ESTABLISHED,
    >and then there's no need for the comment at all.


    Assuming that TCP_ESTABLISHED is defined at that point, which it might
    well not be.

    -- Richard
    --
    "Consideration shall be given to the need for as many as 32 characters
    in some alphabets" - X3.4, 1963.
    Richard Tobin, Jan 19, 2007
    #8
  9. Asbjørn Sæbø wrote:
    > writes:
    >
    >> [...]
    >> Does the FAQ entry <http://c-faq.com/struct/enumvsdefine.html> help?

    >
    > Yes. Although this probably means that the practice I have seen of
    > typedef-ings enums does not help much when it comes to catching
    > errors.


    gcc (and all others out there too, probably) checks switch statements
    for you:

    typedef enum {
    ONE,
    TWO
    } Something;

    void func (Something s)
    {
    switch (s)
    {
    case ONE:
    break;
    } /* warning here - TWO not handled in switch */
    }

    And using enum type instead of int is a good documentation too,
    which is a great help to *avoid* errors in the first place.

    Regards,
    Yevgen
    Yevgen Muntyan, Jan 19, 2007
    #9
  10. Asbjørn Sæbø <> writes:
    > writes:
    > > [...]
    > > Does the FAQ entry <http://c-faq.com/struct/enumvsdefine.html> help?

    >
    > Yes. Although this probably means that the practice I have seen of
    > typedef-ings enums does not help much when it comes to catching
    > errors.


    As far as I can tell, typedef-ing an enum doesn't help *at all* when
    it comes to catching errors. A typedef merely creates an alias for a
    type; it doesn't create a new type.

    Typedefs can be useful when creating an abstract data type (hiding the
    representation details from clients), or when specifying a numeric
    type that may vary from one implementation to another (such as
    int32_t, which could be int, long, etc.) Most other uses of typedefs
    are, in my opinion, not useful; you might as well refer to the
    original type directly.

    --
    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, Jan 20, 2007
    #10
  11. "David T. Ashley" <> writes:
    > "Asbjørn Sæbø" <> wrote in message
    > news:...
    > >
    > > I came over this code which puzzled me. Isn't the enum supposed to
    > > have an identifier?
    > >
    > > enum {
    > > BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
    > > BT_OPEN,
    > > BT_BOUND,
    > > BT_LISTEN,
    > > BT_CONNECT,
    > > BT_CONNECT2,
    > > BT_CONFIG,
    > > BT_DISCONN,
    > > BT_CLOSED
    > > };

    [snip]
    > I don't know the standards, but the code excerpt above behaves about the
    > same as:
    >
    > #define BT_CONNECTED (1)
    > #define BT_OPEN (2)
    > etc.


    Yes, pretty much. Incidentally, the parentheses aren't necessary.
    Parenthesizing macro definitions is an excellent habit, but it's good
    to know that if the definition is a single literal constant, there's
    no way for operator precedence to cause problems.

    Of course the parentheses are harmless; this is an idle comment, not a
    complaint.

    > The only advantage to enums seems to be that they allow the compiler to
    > number the constants itself.


    Yup.

    > In fact, in the example you gave, my code
    > would also traditionally include a symbol like "BT_MAX" at the end to test
    > for a corrupted or unexpected variable (and of course, the value of BT_MAX
    > will be modified if constants are added or removed earlier in the list).


    Which you can do like this:

    enum {
    BT_MIN = 1,
    BT_CONNECTED = BT_MIN,
    BT_OPEN,
    BT_BOUND,
    BT_LISTEN,
    BT_CONNECT,
    BT_CONNECT2,
    BT_CONFIG,
    BT_DISCONN,
    BT_CLOSED,
    BT_MAX = BT_CLOSED
    };

    You still have to fix things if you change the first or last literal,
    but not if you add or remove something in the middle.

    --
    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, Jan 20, 2007
    #11
    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. Kobu
    Replies:
    7
    Views:
    445
  2. Replies:
    2
    Views:
    1,747
  3. Replies:
    2
    Views:
    893
    Owen Jacobson
    Dec 11, 2007
  4. S_K
    Replies:
    0
    Views:
    649
  5. ImpalerCore

    reusing identifier in two enums

    ImpalerCore, Mar 19, 2012, in forum: C Programming
    Replies:
    6
    Views:
    585
    Jens Gustedt
    Mar 21, 2012
Loading...

Share This Page