Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

enum type check in C/gcc

Tags:

See the simple example below. When a function returning one enum is assigned to a variable of a different enum I don't get any warning even with gcc -Wall -pedantic. Why is it not possible for a C compiler to do type checking on enums? Or is it gcc specific? I don't have access to any other compiler right now to try it out..

enum fruit {
APPLE,
ORANGE
};

enum color {
RED,
GREEN
};

static inline enum color get_color() {
    return RED;
}

int main() {
    enum fruit ftype;
    ftype = get_color();
}
like image 345
Manohar Avatar asked Dec 21 '11 22:12

Manohar


People also ask

Is enum a type in C?

Enumeration or Enum in C is a special kind of data type defined by the user. It consists of constant integrals or integers that are given names by a user. The use of enum in C to name the integer values makes the entire program easy to learn, understand, and maintain by the same or even different programmer.

How do you check if an enum is valid?

Enum. IsDefined is a check used to determine whether the values exist in the enumeration before they are used in your code. This method returns a bool value, where a true indicates that the enumeration value is defined in this enumeration and false indicates that it is not.

What is enum type?

An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.

What is the default type of enum in C?

In C programming, an enumeration type (also called enum) is a data type that consists of integral constants. To define enums, the enum keyword is used. enum flag {const1, const2, ..., constN}; By default, const1 is 0, const2 is 1 and so on.


2 Answers

This declaration:

enum fruit {
    apple,
    orange
};

declares three things: a type called enum fruit, and two enumerators called apple and orange.

enum fruit is actually a distinct type. It's compatible with some implementation-defined integer type; for example, enum fruit might be compatible with int, with char, or even with unsigned long long if the implementation chooses, as long as the chosen type can represent all the values.

The enumerators, on the other hand, are constants of type int. In fact, there's a common trick of using a bare enum declaration to declare int constants without using the preprocessor:

enum { MAX = 1000 };

Yes, that means that the constant apple, even though it was declared as part of the definition of enum fruit, isn't actually of type enum fruit. The reasons for this are historical. And yes, it would probably have made more sense for the enumerators to be constants of the type.

In practice, this inconsistency rarely matters much. In most contexts, discrete types (i.e., integer and enumeration types) are largely interchangeable, and the implicit conversions usually do the right thing.

enum fruit { apple, orange };
enum fruit obj;      /* obj is of type enum fruit */
obj = orange;        /* orange is of type int; it's
                        implicitly converted to enum fruit */
if (obj == orange) { /* operands are converted to a common type */
    /* ... */
}

But the result is that, as you've seen, the compiler isn't likely to warn you if you use a constant associated with one enumerated type when you mean to use a different one.

One way to get strong type-checking is to wrap your data in a struct:

enum fruit { /* ... */ };
enum color { /* ... */ };
struct fruit { enum fruit f; };
struct color { enum color c; };

struct fruit and struct color are distinct and incompatible types with no implicit (or explicit) conversion between them. The drawback is that you have to refer to the .f or .c member explicitly. (Most C programmers just count on their ability to get things right in the first place -- with mixed results.)

(typedef doesn't give you strong type checking; despite the name, it creates an alias for an existing type, not a new type.)

(The rules in C++ are a little different.)

like image 76
Keith Thompson Avatar answered Oct 09 '22 00:10

Keith Thompson


Probably most of us understand the underlying causes ("the spec says it must work"), but we also agree that this is a cause of a lot of programming errors in "C" land and that the struct wrapping workaround is gross. Ignoring add-on checkers such as lint, here's what we have:

gcc (4.9): No warning available.
microsoft cl (18.0): No warning available.
clang (3.5): YES -Wenum-conversion
like image 21
Peter M Avatar answered Oct 09 '22 02:10

Peter M