Question about "enums"

I

Ian Collins

Keith said:
Ian Collins said:
Thad Smith wrote:
[snip]
Attempts to assign anything other than an enumeration constant defined
for the associated enumeration type or another enumeration variable of
the same type would be a useful compiler or lint warning. Refusing to
translate in such cases would make the compiler non-conforming.

Maybe this is a topic for comp.std.c, I still think the C standard is
broken in this instance.


I wouldn't say it's broken. The design of enumerated types isn't
ideal, but I don't think it's possible to fix it (though it would be
possible to invent a new feature that doesn't have the drawbacks of
the current types).

For example:

enum foo { a, b };
enum foo e;
int i = 2;
e = i;

In this case, obj is an object of type "enum foo", and the value of i
is assigned to it. The value being assigned doesn't match any of the
enumerators of the type, but there's no way in general to detect this
at compilation time.
You could if enumerated types and int where different types without
automatic conversion, which is the way C++ does it, so you simply can't
assign an int to an enum.
If it's going to be detected at run time, you need to introduce an
entire mechanism for detecting run time errors, something that C
doesn't currently have. And for this particular check, a simple range
check is insufficient; consider replacing the type declaration above
with:

enum foo { a = 1, b = 37 };
Again, if the only legal things you can assign to e are foo named
constants, the error can be flagged at compiler time.
C's enumerated types really don't provide much more than a set of
named constants. There are other languages that have more type-safe
enumerated types (Pascal and Ada, for example), but I don't think it's
likely that C's enumerated types can be significantly improved without
breaking existing code (or the language itself).

If you can come up with a proposal, though, by all means go for it.
Simply remove the automatic conversion from an integer type to an
enumerated type. Automatic conversion form enum to integer types should
be permitted because enumerated types are constrained to a set of
integer values. Thus assignment from enum to int doesn't violate any
constraints.
 
K

Keith Thompson

Ian Collins said:
You could if enumerated types and int where different types without
automatic conversion, which is the way C++ does it, so you simply can't
assign an int to an enum.

I actually agree that that's a better approach. But you can't make
such a change to C without breaking existing code, something the
committee is very hesitant to do. (They don't always entirely avoid
it; for example, the C99 standard added several new keywords.)
 
I

Ian Collins

Keith said:
Ian Collins said:
Keith said:
Ian Collins <[email protected]> writes:
[...]
Maybe this is a topic for comp.std.c, I still think the C standard is
broken in this instance.


I wouldn't say it's broken. The design of enumerated types isn't
ideal, but I don't think it's possible to fix it (though it would be
possible to invent a new feature that doesn't have the drawbacks of
the current types).

For example:

enum foo { a, b };
enum foo e;
int i = 2;
e = i;

In this case, obj is an object of type "enum foo", and the value of i
is assigned to it. The value being assigned doesn't match any of the
enumerators of the type, but there's no way in general to detect this
at compilation time.

You could if enumerated types and int where different types without
automatic conversion, which is the way C++ does it, so you simply can't
assign an int to an enum.


I actually agree that that's a better approach. But you can't make
such a change to C without breaking existing code, something the
committee is very hesitant to do. (They don't always entirely avoid
it; for example, the C99 standard added several new keywords.)
That's the standard (pun intended) argument.

I'd wager it would break a lot of already broken but not tested code :)

Anyway, there's always the fall back of compiler switchs to disable
language features. These are inevitable whenever a standard is updated.

Being able to use enums as type-safe function parameters is worth the
cost, in my opinion.
 
J

John Devereux

Ian Collins said:
Keith Thompson wrote:
That's the standard (pun intended) argument.

I'd wager it would break a lot of already broken but not tested code :)

Don't know if it's "broken", but I do regularly make use of this
"feature" of enum. Often I have a situation where a contiguous range
of integers is legal, but some values are special. For example in an
embedded system I might have a lot of (electrical) signals labelled
0...n. It is quite useful to have the automatic sequential numbering
provided by the enum, also to be able to skip over some "unused", but
still valid, inputs.

enum
{
START=000,
REJECT,
QUEUE,
BRAKE,
/*...*/
ALARM=020,
TEST,
NSIGNALS=040
};

turn_on(REJECT);
turn_off(TEST);

/* hardware test */
for(i=0; i<NSIGNALS; i++)
{
turn_on(i);
delay();
turn_off(i);
}
 
I

Ian Collins

John said:
Don't know if it's "broken", but I do regularly make use of this
"feature" of enum. Often I have a situation where a contiguous range
of integers is legal, but some values are special. For example in an
embedded system I might have a lot of (electrical) signals labelled
0...n. It is quite useful to have the automatic sequential numbering
provided by the enum, also to be able to skip over some "unused", but
still valid, inputs.
Nothing wrong with that, I was referring to code that assigned invalid
values to an enum.
 
K

Keith Thompson

Ian Collins said:
Nothing wrong with that, I was referring to code that assigned invalid
values to an enum.

Since the C standard allows that, code that does it isn't wrong. It's
perfectly legal, and has well-defined semantics, to assign a value to
an enum object that isn't one of the constants defined for the type
(at least as long as the value is between the lowest and highest
values).

For example:

enum foo { FIRST = 0, LAST = 999 };
enum foo obj;
for (obj = FIRST; obj <= LAST; obj ++) {
...
}

Disallow this usage, and you'll break existing valid code.
 
I

Ian Collins

Keith said:
Since the C standard allows that, code that does it isn't wrong. It's
perfectly legal, and has well-defined semantics, to assign a value to
an enum object that isn't one of the constants defined for the type
(at least as long as the value is between the lowest and highest
values).

For example:

enum foo { FIRST = 0, LAST = 999 };
enum foo obj;
for (obj = FIRST; obj <= LAST; obj ++) {
...
}

Disallow this usage, and you'll break existing valid code.
Another construct I'd like to see go the way of the Dodo. But I can see
I'm flogging a dead horse.
 
J

jacob navia

Keith Thompson a écrit :
Since the C standard allows that, code that does it isn't wrong. It's
perfectly legal, and has well-defined semantics, to assign a value to
an enum object that isn't one of the constants defined for the type
(at least as long as the value is between the lowest and highest
values).

For example:

enum foo { FIRST = 0, LAST = 999 };
enum foo obj;
for (obj = FIRST; obj <= LAST; obj ++) {
...
}

Disallow this usage, and you'll break existing valid code.


Why do not use "int"?

Why use an enum when its value is just an int???

For example:

enum foo { FIRST = 0, LAST = 999 };
int obj;
for (obj = FIRST; obj <= LAST; obj ++) {
...
}

Id enums are of any value then at all times the value of an enum object
must be in the legal values of that enum!

If not there is no use actually besides replacing a #define...
 
J

John Devereux

Ian Collins said:
Nothing wrong with that, I was referring to code that assigned invalid
values to an enum.

But how is the the compiler supposed to *know* they were invalid? In
the code you snipped, I only mentioned the "special" values in the
enum, yet in fact any integer could be "valid".

I thought your suggestion was that compilers should reject assignments
of values that are not in the enum declaration.
 
I

Ian Collins

John said:
But how is the the compiler supposed to *know* they were invalid? In
the code you snipped, I only mentioned the "special" values in the
enum, yet in fact any integer could be "valid".
Sorry if I got carried away with the snippers...

The compiler would know because it knows the legal set of values for the
enumeration. For this to work, math operations on enums will have to be
removed. In my opinion, they don't make sense, given a set of integers
{ 1, 5, 7, 9 } what does incrementing a member of the set do?

Restoring your code:

enum
{
START=000,
REJECT,
QUEUE,
BRAKE,
/*...*/
ALARM=020,
TEST,
NSIGNALS=040
};

turn_on(REJECT);
turn_off(TEST);

/* hardware test */
for(i=0; i<NSIGNALS; i++)
{
turn_on(i);
delay();
turn_off(i);
}

I had assumed that i was an int (you didn't show the declaration).
I thought your suggestion was that compilers should reject assignments
of values that are not in the enum declaration.

Indeed it is.
 
K

Keith Thompson

jacob navia said:
Keith Thompson a écrit :

Why do not use "int"?

Why use an enum when its value is just an int???

For example:

enum foo { FIRST = 0, LAST = 999 };
int obj;
for (obj = FIRST; obj <= LAST; obj ++) {
...
}

Id enums are of any value then at all times the value of an enum
object must be in the legal values of that enum!

If not there is no use actually besides replacing a #define...

Enumerated types have a number of advantages over #define. They
automatically assign unique values to each of a sequence of names; you
can do that manually with macros, but it's inconvenient. They're
scoped; macros are visible from the point of definition to the end of
the translation unit. And the compiler takes care of choosing a type
that fits all the specified values.

Certainly the code you suggest is perfectly valid, and probably better
than the example I presented. And if I were designing a new language
from scratch, enums would be distinct types, and there would be no
implicit conversions between enums and integers.

Although C's definition of enumerated types has some real weaknesses,
I don't think it's broken enough to justify changing it -- at least
not in a language that calls itself "C".
 
V

Vladimir Oka

Ian Collins opined:
Sorry if I got carried away with the snippers...

The compiler would know because it knows the legal set of values for
the enumeration. For this to work, math operations on enums will
have to be removed. In my opinion, they don't make sense, given a
set of integers { 1, 5, 7, 9 } what does incrementing a member of the
set do?

Well, for an `enum` it may make sense to "walk" through the list of
allowed values (i.e. `5` + 1 == `7`, in the example above). A bit like
pointer arithmetic, I guess.

I don't see why would that be so useful to make it into the language,
though. And, it would likely break a *lot* of existing code.

IMHO, as they stand `enum`s in C are a bit flawed, but still useful.

--
"How should I know if it works? That's what beta testers are for. I
only coded it."
(Attributed to Linus Torvalds, somewhere in a posting)

<http://clc-wiki.net/wiki/Introduction_to_comp.lang.c>
 
A

August Karlstrom

Ian said:
But not with the following, which I've always considered a huge hole in
the C standard.

enum loop { NO, YES};
enum loop okloop=YES;

void f( enum loop v )
{
}

int main(void)
{
f( 42 );

okloop = 42;

return 0;
}

Compared to other pitfalls in C I think this is a minor one. Note that
the language designer maestro N. Wirth even omitted enumerations in
Oberon (successor to Modula).

Reference: http://www.oberon2005.ru/paper/nw1988d.pdf


August
 
A

ais523

Thad said:
Attempts to assign anything other than an enumeration constant defined
for the associated enumeration type or another enumeration variable of
the same type would be a useful compiler or lint warning. Refusing to
translate in such cases would make the compiler non-conforming.
One problem with this is storing an enum in a file. Obviously, there is
no fprintf format code for a user-defined enum, so normally something
like %d is used when portability is needed (first casting to int). When
reading back from the file, the safe and portable way is to fscanf back
into an int, and then assigning the int to an enum. The suggestion
above would make it very difficult to store any enum in a file.
 
I

Ian Collins

ais523 said:
Thad Smith wrote:



One problem with this is storing an enum in a file. Obviously, there is
no fprintf format code for a user-defined enum, so normally something
like %d is used when portability is needed (first casting to int). When
reading back from the file, the safe and portable way is to fscanf back
into an int, and then assigning the int to an enum. The suggestion
above would make it very difficult to store any enum in a file.
The same problem exists in C++, a simple cast is the solution.
 
J

John Devereux

Ian Collins said:
John Devereux wrote:
Sorry if I got carried away with the snippers...

The compiler would know because it knows the legal set of values for the
enumeration. For this to work, math operations on enums will have to be
removed. In my opinion, they don't make sense, given a set of integers
{ 1, 5, 7, 9 } what does incrementing a member of the set do?

Restoring your code:

enum
{
START=000,
REJECT,
QUEUE,
BRAKE,
/*...*/
ALARM=020,
TEST,
NSIGNALS=040
};

turn_on(REJECT);
turn_off(TEST);

/* hardware test */
for(i=0; i<NSIGNALS; i++)
{
turn_on(i);
delay();
turn_off(i);
}

I had assumed that i was an int (you didn't show the declaration).

Sorry, yes, i was an int. But turn_off() could be declared a taking an
enum argument. But actually I suppose it could just as well be
declared taking an int, and in fact that is what I do in practice.
Indeed it is.

So it would be OK to convert an enum to an arbitrary int, but not an
int to an enum type?
 
I

Ian Collins

John said:
So it would be OK to convert an enum to an arbitrary int, but not an
int to an enum type?
Yes, that's what I'd like to see. This makes enums appropriate for use
as a type safe function parameter.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top