[comp.lang.c] Enum vs Define ===> BUG REPORT

bergsten@chalmers.UUCP (Per Bergsten) (08/03/87)

(Maybe this message should go to comp.bugs.something or sunspots).
The recent discussion about relative merits of the "enum" type made me
remember an obscure bug in PCC I discovered some time ago and (almost) forgot.

The following example should NOT be construed as a discredit to the idea
of enum. I am prepared to accept all the help the language/compiler can give;
I regard "enum" types as a small but not useless tool.

However, current implementations are lacking in quality.
-------------------------------------------------------------------------------
Consider:

	typedef enum { a=0, b=1, c=2 } t1;

	mine()
	{
		printf("mine: a=%d, b=%d, c=%d\n", a, b, c);
	}

	main()
	{
		typedef enum { b=0, c=1, d=2 } t2;

		mine();
		printf("main: b=%d, c=%d, d=%d\n", b, c, d);
		exit(0);
	}

On VAX/BSD 4.2 and on SUN-3/SunOs3.2 I obtain the following output:

	mine: a=0, b=1, c=2
	main: b=1, c=2, d=2
	        ^    ^

In my opinion this is wrong. I do confess I don't have access to a C-standard
document so my understanding of C is largely based on K&R and some 8 years of
practise, nevertheless I don't think that the compiler behaves correctly. At
the very least I would expect an error message if this is an illegal program.
Incidentally: lint (in verbose mode) only prints a warning that "b" and "c" are
redefined.
-------------------------------------------------------------------------------

	Per Bergsten				bergsten@chalmers.se
					........!mcvax!enea!chalmers!bergsten
				a.k.a		perb%holtec.uucp@chalmers

ron@topaz.rutgers.edu (Ron Natalie) (08/04/87)

I'm surprised this works at all.  YOU NEVER DECLARE ANY VARIABLES

decot@hpisod2.HP.COM (Dave Decot) (08/05/87)

> I'm surprised this works at all.  YOU NEVER DECLARE ANY VARIABLES

While the example does not declare any variables, it also does not
refer to any.  a, b, and c are constants.

Dave Decot
hpda!decked

mnc@m10ux.UUCP (Michael Condict) (08/07/87)

In <13700@topaz.rutgers.edu>, ron@topaz.rutgers.edu.UUCP writes:

> I'm surprised this works at all.  YOU NEVER DECLARE ANY VARIABLES

Why do you think he should need to declare any variables in order to obtain
enum constants that can be passed to the printf function?
The confusion displayed by this and previous postings on the subject of enums
in C has been dealt with here before, by a posting from Dennis Ritchie, among
others.  To summarize:

PCC-BASED COMPILERS (System V, BSD, Sun, ...) DO NOT CORRECTLY IMPLEMENT ENUMS.

In fact, they do not even provide an implementation that is useable without
excruciating effort on the part of the user.  Here is the correct definition,
as intended by Ritchie and as described in the System V C Reference Manual
(any mistakes are mine):

	   The occurrence of:
		enum [ tag ] { e_1 [ = val1 ] , ... , e_n [ = val_n ] }
	   (whether or not it is inside a typedef, has an enum tag, or is fol-
	   lowed by declarators declaring variables) should have the effect of
	   introducing n new names, e_1 through e_n, that are of integral type
	   and can be used anywhere an integral const is allowed.  These new
	   names have the same scope (are in the same symbol table) as if
	   they had been introduced by: int e_1, ..., e_n; immediately
	   following the declaration that contains the enum construct.

This implies that the program in the referenced article, which had
roughly the following:

	typedef enum { a=0, b=1, c=2 } t1;
	void main() {
		typedef enum { b=0, c=1, d=2 } t2;
		...

is correct, and the compiler is wrong.  The scope of the first b and c enum
values overlaps with (surrounds) the scope of the second b and c, but they
are different scopes and hence it is legal to redeclare b and c inside the
function, just as it would be legal to do the analogous thing with int
variables named b and c.  The compiler is apparently using one global symbol
table for all enum values, which is severely brain damaged.

The other bug in pcc, which renders its enums almost unuseable, is that
its enums are not type-compatible with ints!  This means that you must cast
them to (int) to use them as an array subscript or to assign them to an int
variable.  Strong typing of enums would be nice as an option, but it is
only reasonable if it does not prevent you from using enums in type-correct ways
in all the contexts that make sense, e.g., as array subscripts.  Since there
is no way to declare that an array has a particular enum type as its index
range, it is unreasonable to have strongly typed enums.

NOTE FOR LANGUAGE LAWYERS:  In the definition I gave above, there appears to
be a glitch.  What if the "enum { ... }" occurs in a field declaration of a
struct or union?  In this case, the obvious desired action is that the scope
of the enum constants be the same as the scope of the surrounding struct/union
type.  Otherwise the field containing the enum construct would be of an enum
type whose values are not directly visible, clearly undesirable.  Well in
fact, strict reading of my words above leads to the desired semantics, because
I said "the declaration containing the ...".  The word "declaration" has a
precise meaning in the published syntax rules for C, and is distinct from
"struct-declaration".  The former refers only to a top-level declaration,
while the latter refers to the declaration of a field within a struct.
So the following:

	struct {
		int x;
		enum {a, b} y;
	} s;

should introduce enum consts a and b whose scope is the same as s, not x.
-- 
Michael Condict		{ihnp4|vax135|cuae2}!m10ux!mnc
AT&T Bell Labs		(201)582-5911    MH 3B-416
Murray Hill, NJ