[comp.lang.c] Are enums safe to use in portable code?

bliss@sp64.csrd.uiuc.edu (Brian Bliss) (01/31/91)

 The alliant fx C compiler (for an fx1 or fx8, not fx2800), supports
 them, but gives errors when you try to compare two enum constants.

 bb

steve@taumet.com (Stephen Clamage) (02/01/91)

bliss@sp64.csrd.uiuc.edu (Brian Bliss) writes:

> The alliant fx C compiler (for an fx1 or fx8, not fx2800), supports
> them, but gives errors when you try to compare two enum constants.

Enums are well-defined and safe in standard (ANSI/ISO) C.  However,
enums were introduced helter-skelter by different vendors years
earlier, with no written standard to refer to.  Apart from compiler
bugs, different implementors had different ideas of how enums should
work.  At least one vendor did not allow an enum to index an array,
for example.  So if you need to port code among lots of pre-standard
or non-standard compilers, it is probably best not to use enums.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

dave@cs.arizona.edu (Dave P. Schaumann) (02/01/91)

bliss@sp64.csrd.uiuc.edu (Brian Bliss) writes:
BB> The alliant fx C compiler (for an fx1 or fx8, not fx2800), supports
BB> them, but gives errors when you try to compare two enum constants.

steve@taumet.com (Stephen Clamage) writes:
SC>Enums are well-defined and safe in standard (ANSI/ISO) C.  However,
SC>[there are pre-ANSI compilers out there that get them wrong].
SC>So if you need to port code among lots of pre-standard
SC>or non-standard compilers, it is probably best not to use enums.

(sarcasm 'on)
Of course, if you want to port to a machine that doesn't have a C compiler
at all, you'd better not even use C.  Maybe you'll want to port to a machine
that doesn't have a compiler that allows floating point numbers.  Better not
use those, either.

Let us all now observe a moment of silence for the god Portability.
(sarcasm 'off)

(soapbox 'on)
Portability is a slippery issue.  People like to treat it like absolute
portability is a reasonable and possible goal.  But it is not possible to
write a program that is absolutely portable to every platform on God's Green
Earth.  (By absolutely portable, I mean compilable/interpretable with *no*
modifications whatsoever).  Absolute portability is a grail no-one can reach.

Realistic portability is balancing a trade-off.  The wider the range of
computers you wish to port to, the fewer language choices you have, and the
fewer language features you can count on to be there and work right.

Even if you restrict yourself to platforms that have some kind of C compiler,
you are still faced with a wildly varying field of language features and
qualities of implementation.  To have even realistic portability, you have
to expect at least a little editing on the target machine (in the general
case).
(soapbox 'off)

If you're porting a program that uses enums to a compiler that doesn't have
enums, or has broken enums, it is a fairly simple proceedure (in fact, it
can be automated) to use #defines as a work-around.

Dave Schaumann		|  And then -- what then?  Then, future...
dave@cs.arizona.edu	|  		-Weather Report

enag@ifi.uio.no (Erik Naggum) (02/01/91)

In article <1991Jan30.210255.16804@csrd.uiuc.edu>, Brian Bliss writes:

    The alliant fx C compiler (for an fx1 or fx8, not fx2800), supports
    them, but gives errors when you try to compare two enum constants.

    bb

Assume these definitions:

	enum { frotz, klutz } foo;					[1]
	enum { gunk, junk } bar;					[2]

Which of these are your compiler complaining against?

	frotz == klutz							[3]
	frotz == gunk							[4]
	frotz < klutz							[5]
	frotz < junk							[6]

The declaration in [1] declares a distinct (anonymous) type of which
foo is an object.  Likewise [2] declares another distinct (anonymous)
type of which bare is an object.  frotz and klutz [1] are names of
constant values of the type of object of which foo is an instance.
Likewise for gunk and junk [2].

This makes the comparison in [3] valid (but slightly pointless), since
we're comparing values of the same type, while the latter does not.

In [5] and [6], "<" could be any of "<", "<=", ">", and ">=".  I'm not
sure about the welldefinedness of these comparisons, since I have seen
compilers barf on expressions such as

	foo < klutz							[7]

since it implicitly entails a conversion to int, which nonetheless is
the base type for enums.  Careful consulting of the ANSI C standard
may be needed to verify this.

It would be helpful if you gave examples of the code on which your
compilers gags, as well as the precise error message produced.

--
[Erik Naggum]	Snail: Naggum Software / BOX 1570 VIKA / 0118 OSLO / NORWAY
		Mail: <erik@naggum.uu.no>, <enag@ifi.uio.no>
My opinions.	Wail: +47-2-836-863	Another int'l standards dude.

sarima@tdatirv.UUCP (Stanley Friesen) (02/05/91)

In article <ENAG.91Feb1003707@hild.ifi.uio.no> enag@ifi.uio.no (Erik Naggum) writes:
>Assume these definitions:
 
>	enum { frotz, klutz } foo;					[1]
>	enum { gunk, junk } bar;					[2]
> ...
>The declaration in [1] declares a distinct (anonymous) type of which
>foo is an object.  Likewise [2] declares another distinct (anonymous)
>type of which bare is an object.

So far so good. ANSI does indeed specify that each enumeration is a distinct
type.

> frotz and klutz [1] are names of
>constant values of the type of object of which foo is an instance.
>Likewise for gunk and junk [2].

However here you deviate from the ANSI standard.
According to 3.5.2.2 (Semantics):
"The identifiers in an enumerator list are declared as constants that
have type int and may appear anywhere such are permitted".

Thus frotz, klutz, gunk, and junk are all *int's*, and may be used anywhere
an int may be used.  This includes *all* forms of comparison, thus:

    (klutz == gunk)

is a perfectly valid ANSI C construct, and evaluates to true if and only if
the value of klutz equals the value of gunk.  (This is also a constant
expression, that can be evaluated wholly by the compiler)

Any C compiler that fails to accept this is *not* ANSI C.  (It may be
a valid pre-ANSI compiler though).
-- 
---------------
uunet!tdatirv!sarima				(Stanley Friesen)

torek@elf.ee.lbl.gov (Chris Torek) (02/14/91)

In article <128@tdatirv.UUCP> sarima@tdatirv.UUCP (Stanley Friesen) writes:
>According to 3.5.2.2 (Semantics):
>"The identifiers in an enumerator list are declared as constants that
>have type int and may appear anywhere such are permitted".

Note, however, that a good compiler can (and probably should) emit a
warning when enumeration constants for different enumerated types
are compared.  That is, given

	enum { apple, pear, orange } fruits;
	enum { lima, green, black } beans;

a good compiler would complain differently about the comparision:

	if (apple == orange)

than about the comparison:

	if (lima == pear)

Both of these are effectively the same as `if (0)', hence a good compiler
should warn about a constant in conditional context as well as mixing
enumeration types (in the second example) and code that is not reached
(assuming there are no labels following the comparisons).  All of these
are legal ANSI C expressions (despite the comparison of apples and oranges).

Incidentally, one apple is worth a lot of Lima beans. :-)
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov