简体   繁体   中英

What's the best way to declare an enum variable in C?

This question arises from an old question:

How to define an enumerated type (enum) in C?

Answers below that question are just conflicting with each other. For example, one answer said "You need to use typedef ", another argued "You don't need a typedef ", a comment under which wrote "You cannot use enum strategy { ... }; in C -- you can and should do it in C++ though." This really confuses me. What's more, that OP's code compiles without even warnings using clang on all my computers.

So, my question is: In C, what's the best practice to use enum variables?

C has two namespaces, one for variables and functions and another for things like enum s and struct s. Let's call the second one the enum namespace.

When you declare an enum like enum Foo {Bar1, Bar2}; , Foo , and the enumeration constants will be put into the enum namespace.

This means that you have to use the enum prefix whenever you want to use that enumeration. Which is a lot of inconvenient typing! (Out of interest, the same applies to struct ).

Fortunately C allows you to borrow things from the enum namespace, so they appear in the variable and function namespace too. You do that using a typedef :

typedef enum Foo {Bar1, Bar2} Foo;

The first Foo is its name in the enum namespace, the second Foo is its name in the function and variable namespace.

You don't need to do this in C++: unless you use namespace explicitly, everything is in the global namespace.

Despite its large number of votes and its highly upvoted answers, the question you reference is based on a completely false premise. It asserts that this code is erroneous in C:

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = IMMEDIATE;

In fact, however, that code is perfectly fine in C89, C99, and C2011. It declares variable strategy to be of an anonymous enumerated type with the given enumeration constants, and it initializes that variable to one of the three values defined for its type. The error messages the OP of that question reported may have been emitted by a non-conforming compiler, or perhaps there was more to the story than that OP presented.

On the other hand, that form of variable declaration is of comparatively little practical use, because no other object can be declared to have the same type as the variable declared there. There are two alternatives for declaring an enumerated type so that it can be used in multiple declarations:

  1. Declare the type with a tag: enum strategy_tag {RANDOM, IMMEDIATE, SEARCH} /* ... */ ;
  2. Use a typedef to name the type: typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy_type;

How you then refer to the type depends on which form you used. If you declare the type as a tagged enum, then you can use it in declarations by referencing the tag:

enum strategy_tag my_strategy = RANDOM;

. If you declare the type as a typedef 'd name then you use the defined name as the type name

strategy_type my_strategy = IMMEDIATE;

. These are not exclusive; you can both tag an enum and declare a typedef for it, in separate statements ...

enum strategy_tag {RANDOM, IMMEDIATE, SEARCH};
typedef enum strategy_tag strategy_type;

... or even in one ...

typedef enum strategy_tag {RANDOM, IMMEDIATE, SEARCH} strategy_type;

. If you use both forms of type declaration then you can use either or both forms of type specifier in variable declarations.

Additionally, be aware that the namespaces for enum tags, type names, and variable names are all separate, so although it might be a bit confusing, you can do this:

typedef enum strategy {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy strategy = RANDOM;
enum strategy strategy2 = strategy;

As for which way is best , the answer is not so clear. If you have an established set of coding conventions that address this question then of course it is best to follow the conventions. If not then you can choose, but be consistent, at least within any given project. I tend to think that typedef s are overused in general, but using then to name enum s is one of the uses I think makes sense. If you do that, however, then I suggest not declaring tags for typedef 'd enum s -- since you're after consistency, explicitly providing a mechanism for in consistency is counterproductive.

This is a bit subjective, but there is an industry de facto standard in C and C++ both. It goes:

If you need to declare instances (variables) of the type, then you should keep type definitions completely separate from the variable declarations.

When you mix them up, the code gets confusing to read. This goes for enums and all other types. Example:

typedef enum
{
  THIS,
  THAT
} mytype_t;

...

mytype_t variable;

However, as a special case: if you don't intend to declare any variables of a certain type, but just want a more readable way than #define to enumerate several integer constants belonging to the same group, then it is fine to do like this:

enum
{
  THIS_CONSTANT = 123,
  THAT_CONSTANT = 567
};

...

int something = THIS_CONSTANT + THAT_CONSTANT;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM