Reputation: 2355
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
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
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
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