DawidPi
DawidPi

Reputation: 2355

Is this enum declaration a standard compliant?

So normally enum's are for declaring group of "constant integers" as another type, that represents something. Eg.

enum Color {RED=0, BLUE, YELLOW};

This is clear. But recently I met following in code. This was in a compiler for embedded systems.

enum State {DISABLED=0, ENABLED=!DISABLED};

And it worked just fine. It behaved as a boolean type. My question is, wheather it (this syntax) is ANSI compliant?

If it is standard compliant, then why would compilers define internally something like _Bool for boolean representation and then in stdbool.h (for C language) they do:

#define bool _Bool
... // here goes definitions of true and false

instead of

enum bool {false=0, true=!false};

Which is much cleaner?

Upvotes: 11

Views: 539

Answers (3)

Keith Thompson
Keith Thompson

Reputation: 263177

Yes, the declaration is perfectly valid and portable in both C and C++.

In both C and C++, this:

enum State {DISABLED=0, ENABLED=!DISABLED};

is exactly equivalent to this:

enum State {DISABLED=0, ENABLED=1};

and to this:

enum State {DISABLED, ENABLED};

but for subtly different reasons.

In C, the unary ! operator yields a result of type int, with value either 0 (if the operand is not equal to 0) or 1 (if the operand is equal to 0). !x is equivalent to x == 0. (Any non-zero value is treated as true when used as a condition, but the ! and == operators, among others always yield a result of exactly 0 or 1.) Enumeration constants are always of type int; if a value is specified, it's converted to int if necessary.

(C added type _Bool in the 1999 standard, but all operators that yield logically "boolean" values still yield results of type int.)

In C++, the result of the unary ! operator is of type bool. The result is false or true where C's ! operator would yield 0 or 1, respectively. As in C, if a value is specified, it's converted as needed; the bool values false and true convert to 0 and 1, respectively.

In C, enumeration constants are always of type int. In C++, they're of the enumeration type, in this case enum State.

Referring to an earlier enumeration constant within the same type declaration is legal. Each enumeration constant becomes visible after it's declared.

As for something like:

enum bool { false = 0, true = !false );

being clearer than

enum bool { false = 0, true = 1 };

(in C; it would be illegal in C++), I respectfully disagree. The constant 1 is perfectly clear to anyone familiar with C. Rewriting it as !false is not helpful. In fact, when <stdbool.h> is not available (something that's rare these days), I've used:

typedef enum { false, true } bool;

The fact that false and true will be given their correct values is IMHO sufficiently obvious.

As for why C99 didn't use an enum definition like that, I suspect it's because each enumeration type is compatible with some implementation-defined integer type. (For gcc, it's usually unsigned int or int.) The committee wanted _Bool to be a distinct type with a conversion rank lower than any other integer type. (And they couldn't make bool a keyword without breaking existing code.)

Upvotes: 3

Vlad from Moscow
Vlad from Moscow

Reputation: 310910

According to the C Standard (6.2.1 Scopes of identifiers)

Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list

The same is valid in C++ (3.3.2 Point of declaration)

5 The point of declaration for an enumerator is immediately after its enumerator-definition.[ Example:

const int x = 12;
{ enum { x = x }; }

Here, the enumerator x is initialized with the value of the constant x, namely 12. —end example ]

So you may use already defined enumerators in definitions of next enumerators in an enumeration.

As for the C type _Bool then it appeared in the C 99. Before this standard there are used either manifest constants or enumerations in C.

There is no sense to define an enumeration like this

enum bool {false=0, true!=false};

because type _Bool is already has two values 0 and 1.

Upvotes: 3

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

Yes, this is standard-compliant.

!DISABLED is a valid constant expression, which is all that is required for an enum value.

enum State {DISABLED=0, ENABLED= (!DISABLED)};
//                               ^^^^^^^^^^^

At the point where DISABLED is referenced, the compiler knows its value, so it can compute the value of the expression derived from it, i.e. !DISABLED. It is a fancy way of writing ENABLED=1.

Upvotes: 6

Related Questions