Topic: enum - results undefined


Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/03/05
Raw View
In article <36D59E8C.262A7892@technologist.com>, David R Tribble
<dtribble@technologist.com> writes
>It still remains impossible to define in C (in a conforming way)
>an enum type, which possibly uses an underlying type of 'unsigned
>int', having any (unsigned) enum constants greater than INT_MAX.

Which is because no enum constant may be greater than INT_MAX.

I don't see the problem.

>What, then, is the point of
>allowing the compiler to use 'unsigned int' for an enum type if
>that enum type can't hold any [defined enum constant] values of
>type 'unsigned int'?

The same point as allowing it to use 'signed short' for an enum type
even though no defined enum constants have type 'signed short'. That is:
efficiency in the implementation, should one type work better than
another in the context.

Enumerated types are intended to hold values in the range INT_MIN to
INT_MAX. An implementer is free to widen this if they want, but that's
all we decided to guarantee.

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/02/26
Raw View
In article <36D4623E.F3989E4E@technologist.com>, David R Tribble
<dtribble@technologist.com> writes
>If all of the constant members of the enum type are signed, why would
>the implementation bother to choose an unsigned underlying type?

I don't know, but then I'm not an implementer. No doubt they would have
a good reason.

>Oh, wait, now I see.  You should have said:
>  If all of the initialization expressions are 'signed int'
>  expressions with positive values, then the implementation can
>  choose to use a /smaller/ unsigned integral type as the
>  underlying type.
>
>By /smaller/ we mean 'smaller than int'.

No. It can choose to use unsigned long long if it wants.

And it can't use a smaller type if that type couldn't hold all the
enumerators.

>The prototypical example is allowing the compiler to use 'unsigned
>char' for an enum type having constants within the range
>[0,UCHAR_MAX].

That's allowed, yes.

>But it still remains impossible to define (in a conforming way) an
>enum type with 'signed int' initialization expressions that uses
>an underlying type of 'unsigned int'.

enum fred { jim, sheila };

This could be compatible with *any* integer type, and the implementer
can choose any one. There's no requirement to use the *smallest*.

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/02/26
Raw View
David R Tribble wrote:
>> But it still remains impossible to define (in a conforming way) an
>> enum type with 'signed int' initialization expressions that uses
>> an underlying type of 'unsigned int'.

James Kuyper wrote:
> No. It's only impossible to define one that is REQUIRED to use
> 'unsigned int'. Any implementation can choose to use 'unsigned int'
> for any enumeration that has no negative initialization expressons.

Ah, yes, you're correct.

Let me rephrase my argument...

It still remains impossible to define in C (in a conforming way)
an enum type, which possibly uses an underlying type of 'unsigned
int', having any (unsigned) enum constants greater than INT_MAX.
Which seems like a waste (of at least one bit).

Example:
    // This works in C++ but not C.
    // Assumes 16-bit ints.

    enum Access
    {
        A_NONE =   0x0000,
        A_READ =   0x0001,
        ...
        A_WRITE =  0x4000,
        A_DELETE = 0x8000,  // illegal
        A_ALL =    0xFFFF   // illegal
    };

In C, I can only define non-negative enum constants for any given
enum type, even though the compiler is free to use 'unsigned int'
for its actual type.  Even though the extra bit is there, I can't
use it or even give it a name.  What, then, is the point of
allowing the compiler to use 'unsigned int' for an enum type if
that enum type can't hold any [defined enum constant] values of
type 'unsigned int'?

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@West.sun.com (Stanley Friesen [Contractor])
Date: 1999/02/24
Raw View
In article <erD+uQAku902EwRJ@on-the-train.demon.co.uk>,
Clive D.W. Feather <clive@demon.net> wrote:
>
>In article <7ave4s$829@abyss.West.Sun.COM>, Stanley Friesen [Contractor]
><stanley@West.sun.com> writes
>>So, unless C9X is intended to allow function overloading (multiple
>>functions with the same name, but different call signatures),
>
>This would require several dead bodies for it to be done over.

I kinda figured it was like that, but I haven't been following the
current effort.

Thus, we conclude that the differences in treatment of enum's between
C and C++ are there for good reasons, and should stay different.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <dtribble@technologist.com>
Date: 1999/02/24
Raw View
clamage@Eng.Sun.COM (Steve Clamage) wrote:
>> Your code isn't portable even in C. There is no requirement
>> that sizeof(enum)==sizeof(int) unless the range of the enum
>> is comparable to the range of type int.

Ziv Caspi wrote:
> Live and learn. In 10 years of programming in C I always
> thought that this was assured.

Neither C nor C++ guarantee that
    sizeof(enum Color) == sizeof(int)

On the other hand, C (C89 and C9X) does guarantee that
    sizeof(RED) == sizeof(signed int)
for enum constant 'RED'.

C++ does not gurantee this, though.  It instead guarantees that
    sizeof(RED) == sizeof(enum Color)
where 'RED' is a member of 'enum Color'.  But C does not guarantee
this.

      Expression                     |  C  | C++
  -----------------------------------+-----+-----
  sizeof(enum Color) == sizeof(int)  |  ?  |  ?
  sizeof(RED) == sizeof(signed int)  |  T  |  ?
  sizeof(RED) == sizeof(enum Color)  |  ?  |  T

Enums one area of inconsistency between C and C++.

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: John Aldridge <jpsa@jjdash.demon.co.uk>
Date: 1999/02/24
Raw View
In article <erD+uQAku902EwRJ@on-the-train.demon.co.uk>, Clive D.W.
Feather <clive@on-the-train.demon.co.uk> writes

>In article <7ave4s$829@abyss.West.Sun.COM>, Stanley Friesen [Contractor]
><stanley@West.sun.com> writes

>>So, unless C9X is intended to allow function overloading (multiple
>>functions with the same name, but different call signatures),

>This would require several dead bodies for it to be done over.

Of course, C9X fully understands that function overloading is a
necessary part of a quality programming language; but to get it past
those un-dead bodies it called it "Type-generic macros".  Half :-)
--
Cheers,
John


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Antoine Leca <Antoine.Leca@renault.fr>
Date: 1999/02/25
Raw View
David R Tribble wrote:
>
> (This was cross-posted to both comp.std.c and comp.std.c++.)

Note: I am from the comp.std.c side.

> Merging the replies of Clive D.W. Feather in the C (C9X) camp and
> Allan W in the C++ camp, I arrive at some interesting inconsistencies
> between the two languages.  (I'm ignoring C89 here.)
>
> Example 1:
>     // Assume that 'int' is 16-bit 2's-compl
>     enum Color
>     {
>         BLACK = 0x0000,
>         GREY =  0x7FFF,
>         WHITE = 0xFFFF
>     };
>
> In C9X, all enum constant initialization expressions must be 'signed
> int', so WHITE is apparently initialized to an illegal value.

This is even a constraint, so the above code needs to be diagnosed.


> Given only the first two enum constants, enum Color would have an
> underlying type of 'signed int'.
>
> (If WHITE had a valid initialization value, the underlying type
> would be 'unsigned int'.

Or long.
Or even int, with a conversion from 0xFFFF to -1.
Everything is possible, as we are outside the specifications of
the language.


> However, Clive's comment that initialization expressions must
> be 'signed int' makes this clearly impossible.
                                     ^^^^^^^^^^
I'll prefer "outside the C standard's realm".
Because some compilers accept this construction.

> Which seems to contradict the rule that the underlying
> type of a enum can be 'unsigned int'.  What gives?  How do you
> define an enum type with an underlying type of 'unsigned int' if
> all of the enum constant initialization expressions must be type
> 'signed int'?)

If all constants are positive, then an implementation is allowed
to choose unsigned int as underlying type.
In fact, nothing seems to prevent an implement to choose
long either...


> Regardless of the underling type of enum Color, all of the enum
> constants have type 'signed int' in C9X.

Yes. According to C9X FCD 6.7.2.2p3 (was 6.5.2.2 in C90 and CD1):
  [#3]  The  identifiers in an enumerator list are declared as
  constants that have type int and may  appear  wherever  such
  are  permitted.96) [...]

and to C9X FCD 6.4.4.3p2 (was 6.1.3.3p2 in C90 and CD1):
  6.4.4.3  Enumeration constants

  Syntax

  [#1]

          enumeration-constant:
                  identifier

  Semantics

  [#2] An identifier declared as an enumeration  constant  has
  type int.

  Forward references:  enumeration specifiers (6.7.2.2).


Furthermore, FCD C9X 6.4.4p2 (was 6.1.3p2 in C90 and CD1) says:
  6.1.3  Constants

  Syntax

  [#1]

          constant:
                  floating-constant
                  integer-constant
                  enumeration-constant
                  character-constant

  Constraints

  [#2] The value of a  constant  shall  be  in  the  range  of
  representable values for its type.


<snip>
> Example 7:
>     // Assume that 'int' is 16-bit 2's-compl
>     enum Span
>     {
>         SMALL = 0,
>         BIG =   0x7FFF,
>         HUGE
>     };

This breaks the last constraint I quoted above.
So again we are outside the C standard realm.


> Example 8:
>     // Assume that 'int' is 16-bit 2's-compl
>     enum Bits
>     {
>         LEFT =   0x00000001,
>         MIDDLE = 0x00004000,
>         RIGHT  = 0x00010000
>     };
>
> In C9X, the initialization expression for RIGHT is invalid because
> it exceeds the range of 'signed int'.  RIGHT, as written, cannot
> be used as an enum constant.

Applying the same reasonment as above, you can also says its value
is 0.  ;-)

BTW, many compilers that will accept the above forms (i.e. not in
pedantic ANSI mode), will choose the underlying type to be long
(including for enum Color and enum Span).


> Do these examples constitute a fair summary of the situation for
> the two languages?

Since all situations are outside the C standard, I consider that
you are describing (quite well) C++ extensions w.r.t. the C standard.


> If so, should we issue a defect report for C9X to bring the semantics
> of enums more into agreement with C++?

Why?
What matters is how real-world implementations will proceed.
I expect C/C++ compilers to follow C++ (and in pedantic C mode, they
will issue the appropriate diagostics).  So the problem will only
be of concern to C-only compilers that want to allow this as an
extension.  Your summary is of interest to them.  Perhaps it is
adequate to include such material in the C Rationale?


Antoine
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/02/25
Raw View
In article <36d3a211.43542270@news.netvision.net.il>,
Ziv Caspi <zivc@peach-networks.com> wrote:
>
>There lies the problem. While it is very easy for me to tell users of
>my code "do not create enumerations whose abosolute value is
>larger than MAX_INT", C++ gives me no mechanism to verify that
>in a useful manner.

Which is appropriate, since such enumerators are *legal* in C++.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/02/25
Raw View
(Note: This post describes C behavior, not C++.)

James Kuyper wrote:
>
> David R Tribble wrote:
> ...
> > type of a enum can be 'unsigned int'.  What gives?  How do you
> > define an enum type with an underlying type of 'unsigned int' if
> > all of the enum constant initialization expressions must be type
> > 'signed int'?)
>
> If all of the initialization expressions are 'signed int' expressions
> with positive values, then the implementation can choose to use an
> unsigned integral type as the underlying type.

If all of the constant members of the enum type are signed, why would
the implementation bother to choose an unsigned underlying type?

Oh, wait, now I see.  You should have said:
  If all of the initialization expressions are 'signed int'
  expressions with positive values, then the implementation can
  choose to use a /smaller/ unsigned integral type as the
  underlying type.

By /smaller/ we mean 'smaller than int'.

The prototypical example is allowing the compiler to use 'unsigned
char' for an enum type having constants within the range
[0,UCHAR_MAX].

But it still remains impossible to define (in a conforming way) an
enum type with 'signed int' initialization expressions that uses
an underlying type of 'unsigned int'.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/02/25
Raw View
Clive D.W. Feather wrote:
>
> In article <36D30D32.63C77840@technologist.com>, David R Tribble
> <dtribble@technologist.com> writes
> >Merging the replies of Clive D.W. Feather in the C (C9X) camp and
> >Allan W in the C++ camp, I arrive at some interesting inconsistencies
> >between the two languages.  (I'm ignoring C89 here.)
>
> Hmm. See below concerning C89.
>
> >Example 1:
> >    // Assume that 'int' is 16-bit 2's-compl
> >    enum Color
> >    {
> >        BLACK = 0x0000,
> >        GREY =  0x7FFF,
> >        WHITE = 0xFFFF
> >    };
> >In C9X, all enum constant initialization expressions must be 'signed
> >int', so WHITE is apparently initialized to an illegal value.
>
> Right.
>
> >Given only the first two enum constants, enum Color would have an
> >underlying type of 'signed int'.
>
> No. It could be unsigned int, or [un]signed long [long], or (since short
> must be at least 16 bits) [un]signed short. If chars were 16 bits it
> could be char. Or it could be uint25_t. Or ...
>
> >However, Clive's comment that
> >initialization expressions must be 'signed int' makes this clearly
> >impossible.  Which seems to contradict the rule that the underlying
> >type of a enum can be 'unsigned int'.  What gives?
>
> The initialization expressions, and the enumeration constants, have type
> signed int. The enumerator type is compatible with *some* integer type
> that can hold all the enumeration constants.
>
> >Example 2:
> >    // Assume 'enum Color' is 16-bit 'unsigned int'
> >    enum Color   c = BLACK;
> >    int          i;
> >
> >    i = c;               // 1A
> >    i = BLACK;           // 1B
> >    c = (enum Color) i;  // 2
> >
> >In both C9X and C++, all three assignments are well-defined.
>
> But only because BLACK can be represented in int. In the case of C9X and
> int, there's no problem. With i changed to (say) short, there could be.
>
> >Example 3:
> >    c = (enum Color) 0x4000;   // 3
> >    c = (enum Color) -1;       // 4
> >
> >Assignment (3) is well-defined in both C9X and C++, because c has
> >enough bits to hold the value 0x4000.  Assignment (4) is undefined,
> >because -1 is out of the range of the underlying type of 'unsigned
> >int'.
>
> No. In C9X, since c is compatible with an unsigned type, the -1 is
> converted by adding one more than the maximum value of the type. So it
> becomes 0xFFFF in this case.
>
> >Example 6:
> >    if (WHITE < 0) ...   // C
> >
> >In C9X, all enum constants are type 'signed int', so WHITE is
> >converted from 0xFFFF to -1, and the result of the comparison with
> >0 is 'true'.
>
> Except that WHITE wasn't a valid enum constant, so this would have had a
> diagnostic at compile time, so:
>
> >So C9X and C++ apparently get different results for (C), due to
> >different type promotion rules.
>
> is wrong.
>
> >Example 7:
> >    // Assume that 'int' is 16-bit 2's-compl
> >    enum Span
> >    {
> >        SMALL = 0,
> >        BIG =   0x7FFF,
> >        HUGE
> >    };
> >
> >In both C9X and C++, the underlying type for enum Span is 'unsigned
> >int', because the ranges of values exceed the range of 'signed int'.
>
> Nope; in C9X this would violate a constraint and a diagnostic would be
> required (the expression BIG+1, though never actually written, *is* the
> expression that defines the value of the enumeration constant and thus
> must fit in a signed int).
>
> >Do these examples constitute a fair summary of the situation for
> >the two languages?
>
> Other than as I've commented, yes.
>
> The intention of the wording changes in this area of C9X is purely to
> clean up ambiguities, though an effect of that has been to change the
> promotion rules if the underlying type is unsigned int. We expect that
> any sensible C89 implementation would conform to C9X unchanged.
>
> >If so, should we issue a defect report for C9X to bring the semantics
> >of enums more into agreement with C++?
>
> No. You should issue a defect report for C++ to bring the semantics of
> enums more into agreement with C. Particularly since C was there first.

Since all three examples which should produce different behaviour
in C and C++ are actually invalid in C, I don't see the need of
a defect report for C++. The fact that C++ allows code that C
does not allow is no defect, but intentional. A problem would
only arise if some code that is valid C++ code _and_ valid C
code would produce different results in C++ than in C.
Such code was not shown here.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/02/25
Raw View
Siemel Naran wrote:
>
> On 23 Feb 1999 19:55:49 GMT, Steve Clamage <stephen.clamage@sun.com> wrote:
> >sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:
>
> >>#define MAKE_bitenum_operators(Enum,utype) \
>
> >Enum operator|(Enum lhs, Enum rhs) { return Enum( lhs | rhs ); }
>
> The stuff in {...} calls itself recursively
>
> Enum operator|(Enum lhs, Enum rhs)
> {
>    return Enum( lhs | rhs ); // calls operator|(Enum,Enum)
> }
>
> On como, the program just hangs because the function calls itself
> forever.  Then I must press Ctrl-C to break.
>
> On egcs, the program calls a segmentation fault because the stack
> overflows.
>
> >Enum operator&(Enum lhs, Enum rhs) { return Enum( lhs & rhs ); }
> >Enum operator^(Enum lhs, Enum rhs) { return Enum( lhs ^ rhs ); }
>
> Similar remarks.
>
> >An enumerator in an expression is automatically promoted to an
> >integer type that depends on its underlying type. (See 4.5 in
> >the standard.)
>
> The problem is that since a best match function is available
> -- namely operator|(Enum,Enum) -- the conversion from Enum to
> integer does not occur.

What about this (untested):

inline Enum enum_or(Enum lhs, Enum rhs)
{
  return Enum(lhs | rhs); // operator|(Enum, Enum) not yet defined
}

inline Enum operator|(Enum lhs, Enum rhs)
{
  return enum_or(lhs, rhs); // no recursion here
}

This could be macroized, too:

#define MAKE_OPERATORS(Enum) \
inline Enum Enum_or(Enum lhs, Enum rhs) { return Enum(lhs | rhs); } \
inline Enum operator|(Enum lhs, Enum rhs) { return Enum_or(lhs, rhs); }
\
same for & and ^

Making this a template should be problematic, though
(due to late binding of dependant functions).
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: zivc@peach-networks.com (Ziv Caspi)
Date: 1999/02/25
Raw View
On 25 Feb 99 05:04:51 GMT, stanley@West.Sun.COM (Stanley Friesen
[Contractor]) wrote:

>In article <36d3a211.43542270@news.netvision.net.il>,
>Ziv Caspi <zivc@peach-networks.com> wrote:
>>
>>There lies the problem. While it is very easy for me to tell users of
>>my code "do not create enumerations whose abosolute value is
>>larger than MAX_INT", C++ gives me no mechanism to verify that
>>in a useful manner.
>
>Which is appropriate, since such enumerators are *legal* in C++.

So are assignment operators, yet C++ allows you to declare one as
private with no imlpementation, so as to allow the programmer to
state: "No direct copying of objects of this class, please".

The conceptual difference is clear: The standard gives programmers
some help when they create classes that are used by others, but
offers no such help for people who, through macros, provide
frameworks for others. (I guess nobody thought that the case where
one person writes the enumeration header and another writes
the actual tags is common enough to warrant special consideration.)
This brings me to the issue of post-processing, which I'll postpone
to a later post, to save you all the headache.


---------------------------------------------
Ziv Caspi
zivca@netvision.net.il
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/02/25
Raw View
Stanley Friesen [Contractor] wrote:
>
> In article <36d3a211.43542270@news.netvision.net.il>,
> Ziv Caspi <zivc@peach-networks.com> wrote:
> >
> >There lies the problem. While it is very easy for me to tell users of
> >my code "do not create enumerations whose abosolute value is
> >larger than MAX_INT", C++ gives me no mechanism to verify that
> >in a useful manner.
>
> Which is appropriate, since such enumerators are *legal* in C++.

You _can_ test for this, if you demand two special enumerators,
namely MyEnum_MIN = INT_MIN and MyEnum_MAX = INT_MAX.

Then you can test with the following assert (or an analog assertion
template):

assert(MyEnum_MIN == INT_MIN &&
       MyEnum_MAX == INT_MAX && // test that limit enums are correct
       sizeof(MyEnum) == sizeof(int)); // now non-ints increase size

You loose possible space optimisations, though.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1999/02/25
Raw View
David R Tribble wrote:
>
> (Note: This post describes C behavior, not C++.)
>
> James Kuyper wrote:
> >
> > David R Tribble wrote:
> > ...
> > > type of a enum can be 'unsigned int'.  What gives?  How do you
> > > define an enum type with an underlying type of 'unsigned int' if
> > > all of the enum constant initialization expressions must be type
> > > 'signed int'?)
> >
> > If all of the initialization expressions are 'signed int' expressions
> > with positive values, then the implementation can choose to use an

Correction: change 'positive' to 'non-negative'

> > unsigned integral type as the underlying type.
>
> If all of the constant members of the enum type are signed, why would
> the implementation bother to choose an unsigned underlying type?

Because it can. The choice needn't be any bother at all, at least from
the implementor's point of view. The implicit conversions of expressions
involving enerators to 'unsigned' may be inconvenient for the
programmer, but that's a different issue.

> Oh, wait, now I see.  You should have said:
>   If all of the initialization expressions are 'signed int'
>   expressions with positive values, then the implementation can
>   choose to use a /smaller/ unsigned integral type as the
>   underlying type.
>
> By /smaller/ we mean 'smaller than int'.

It's perfectly true that a smaller integral type is permitted, and the
smaller size provides a motivation for the choice. However, I was
talking about what's permitted, not what's desired. An implementation
can choose to store an enumeration whose only enumerator is 0, in a
64-bit unsigned int. That's wasteful, but legal. (It may even be
efficient, on some architectures.)

...
> But it still remains impossible to define (in a conforming way) an
> enum type with 'signed int' initialization expressions that uses
> an underlying type of 'unsigned int'.

No. It's only impossible to define one that is REQUIRED to use 'unsigned
int'. Any implementation can choose to use 'unsigned int' for any
enumeration that has no negative initialization expressons.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/02/25
Raw View
In article <36D43602.61AE3324@physik.tu-muenchen.de>, Christopher
Eltschka <celtschk@physik.tu-muenchen.de> writes
>> No. You should issue a defect report for C++ to bring the semantics of
>> enums more into agreement with C. Particularly since C was there first.
>
>Since all three examples which should produce different behaviour
>in C and C++ are actually invalid in C, I don't see the need of
>a defect report for C++.

See "sarcasm".

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/02/22
Raw View
In article <36d03430.32434237@news.netvision.net.il>, Ziv Caspi
<zivc@peach-networks.com> writes
>If I could sneak in a related question -- Why doesn't C++ allow the
>programmer to specify the underlying type? (Something like
>"enum E : int { ... };")
>
>(I have a multitude of nifty macros to manipulate enumerations, and
>they all assume that "sizeof enum whatever == sizeof int"; I wish
>there was a portable way to move them to C++.)

IMO macros have no place in C++ source code (well not quite, things such
as sentinels for header files are OK).


Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/02/23
Raw View
zivc@peach-networks.com (Ziv Caspi) writes:

>If I could sneak in a related question -- Why doesn't C++ allow the
>programmer to specify the underlying type? (Something like
>"enum E : int { ... };")

>(I have a multitude of nifty macros to manipulate enumerations, and
>they all assume that "sizeof enum whatever == sizeof int"; I wish
>there was a portable way to move them to C++.)

Your code isn't portable even in C. There is no requirement
that sizeof(enum)==sizeof(int) unless the range of the enum
is comparable to the range of type int.

I think I don't want to know why you are manipulating enums
with macros that depend on knowing the size, so I won't ask.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/02/23
Raw View
Steve Clamage wrote:

[...]

> But the range that can be represented by the underlying type is
> still not directly relevant. From the declaration of the enum
> type, you compute the number of bits necessary to represent the
> range of the declared values. (Unless a negative enumerator is
> specified, that range is non-negative.) Any value that can be
> represented in that number of bits can be converted to that
> enum type. Attempting to convert a value outside that range
> (which is not necessarily as large as the range of the underlying
> type) has undefined results.  Refer to 7.2 paragraph 6 in the C++
> standard.
>         // C++ example
>         enum E { e0, e1=5 };
>         E s = (E)4;   // well-defined
>         E m = (E)6;   // undefined result
>         E l = (E)129; // undefined result

Shouldn't (E)6 be well-defined?

If I understand correctly, e0 is 0, e1 is 5.
Now 5 is binary 101 (since there's no negative enumerator,
unsigned values can be used, and a leading 1 does not hurt).
Since 101 are 3 digits, all numbers which can be represented
with three digits should be allowed.
Now 6 is binary 110, so I would conclude, (E)6 is well-defined.

So what's wrong - your example, or my analysis?


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: zivc@peach-networks.com (Ziv Caspi)
Date: 1999/02/23
Raw View
On 23 Feb 99 09:54:46 GMT, clamage@Eng.Sun.COM (Steve Clamage) wrote:

>Your code isn't portable even in C. There is no requirement
>that sizeof(enum)==sizeof(int) unless the range of the enum
>is comparable to the range of type int.

Live and learn. In 10 years of programming in C I always
thought that this was assured.

>I think I don't want to know why you are manipulating enums
>with macros that depend on knowing the size, so I won't ask.

Since macros get a lot of bad PR in this newsgroup, I'll explain
(without being asked). I'm using a large set of macros to define
in a C++ file the layout of objects in memory, so that I could,
in run time, input commands from the user:

  SET g_Configuration.Threads[LogonThread].EnableDebugging = TRUE

and then set the proper flag in memory. The parsing is all automatic.
I currently handle all the basic types I use (such as chars, ints,
etc.). Having unknown size of enumerations makes things more
complicated then they really should.

(Someone suggested using a MAX_VALUE sentinel in each enumeration.
This works only if I know in advance that the user is not going to
define an enumeration larger than the size I picked for MAX_VALUE.)

---------------------------------------------
Ziv Caspi
zivca@netvision.net.il


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/02/23
Raw View
On 23 Feb 99 09:54:46 GMT, Steve Clamage <clamage@Eng.Sun.COM> wrote:

>I think I don't want to know why you are manipulating enums
>with macros that depend on knowing the size, so I won't ask.

It's nice to know the underlying type of an enum.
A typedef enum::utype would be good.
Anyway, I've written these macros to write overloaded operators.

#define MAKE_bitenum_operators(Enum,utype) \
   Enum operator|(Enum lhs, Enum rhs) { return Enum(utype(lhs)|utype(rhs)); } \
   Enum operator&(Enum lhs, Enum rhs) { return Enum(utype(lhs)&utype(rhs)); } \
   Enum operator^(Enum lhs, Enum rhs) { return Enum(utype(lhs)^utype(rhs)); }


enum Silly { A=0x01, B=0x02, C=0x04 };
MAKE_bitenum_operators(Silly,unsigned);


I would prefer to use templates or something like that, but unfortunately
I can't see a way.  The other way is to write a class

class Silly
{
   public:
      static const Silly A; // =0x01
      static const Silly B; // =0x02
      static const Silly C; // =0x04

      //etc
};

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/02/23
Raw View
sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:

>On 23 Feb 99 09:54:46 GMT, Steve Clamage <clamage@Eng.Sun.COM> wrote:

>>I think I don't want to know why you are manipulating enums
>>with macros that depend on knowing the size, so I won't ask.

>It's nice to know the underlying type of an enum.
>A typedef enum::utype would be good.
>Anyway, I've written these macros to write overloaded operators.

>#define MAKE_bitenum_operators(Enum,utype) \
>   Enum operator|(Enum lhs, Enum rhs) { return Enum(utype(lhs)|utype(rhs)); } \
>   Enum operator&(Enum lhs, Enum rhs) { return Enum(utype(lhs)&utype(rhs)); } \
>   Enum operator^(Enum lhs, Enum rhs) { return Enum(utype(lhs)^utype(rhs)); }

But you don't need to know the underlying type. You need only write

Enum operator|(Enum lhs, Enum rhs) { return Enum( lhs | rhs ); }
Enum operator&(Enum lhs, Enum rhs) { return Enum( lhs & rhs ); }
Enum operator^(Enum lhs, Enum rhs) { return Enum( lhs ^ rhs ); }

An enumerator in an expression is automatically promoted to an
integer type that depends on its underlying type. (See 4.5 in
the standard.)

You can always cast values of that type back to the original type
if you haven't created a value outside the enumerator's "extended
range". The bitwise operators above don't cause any range problems,
so you don't need to know the underlying type.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <dtribble@technologist.com>
Date: 1999/02/23
Raw View
(This was cross-posted to both comp.std.c and comp.std.c++.)

Merging the replies of Clive D.W. Feather in the C (C9X) camp and
Allan W in the C++ camp, I arrive at some interesting inconsistencies
between the two languages.  (I'm ignoring C89 here.)

Example 1:
    // Assume that 'int' is 16-bit 2's-compl
    enum Color
    {
        BLACK = 0x0000,
        GREY =  0x7FFF,
        WHITE = 0xFFFF
    };

In C9X, all enum constant initialization expressions must be 'signed
int', so WHITE is apparently initialized to an illegal value.
Given only the first two enum constants, enum Color would have an
underlying type of 'signed int'.

(If WHITE had a valid initialization value, the underlying type
would be 'unsigned int'.  However, Clive's comment that
initialization expressions must be 'signed int' makes this clearly
impossible.  Which seems to contradict the rule that the underlying
type of a enum can be 'unsigned int'.  What gives?  How do you
define an enum type with an underlying type of 'unsigned int' if
all of the enum constant initialization expressions must be type
'signed int'?)

Regardless of the underling type of enum Color, all of the enum
constants have type 'signed int' in C9X.

In C++, all three enum constants are legal, and the underlying type
for enum Color is 'unsigned int'.  The type of the enum constants
is also, apparently, 'unsigned int'.


Example 2:
    // Assume 'enum Color' is 16-bit 'unsigned int'
    enum Color   c = BLACK;
    int          i;

    i = c;               // 1A
    i = BLACK;           // 1B
    c = (enum Color) i;  // 2

In both C9X and C++, all three assignments are well-defined.
Assignments (1A) and (1B) do not require an explicit cast in either
language.

Assignment (2) requires an explicit cast only on C++, where an
object of type 'enum Color' cannot be directly assigned a value of
type 'int'.


Example 3:
    c = (enum Color) 0x4000;   // 3
    c = (enum Color) -1;       // 4

Assignment (3) is well-defined in both C9X and C++, because c has
enough bits to hold the value 0x4000.  Assignment (4) is undefined,
because -1 is out of the range of the underlying type of 'unsigned
int'.


Example 4:
    c = WHITE;
    if (c < -2) ...      // A

In C9X, the underlying type of 'c' is 'unsigned int', which causes
the '-2' to be cast to 'unsigned int' (-2 => 0xFFFE) prior to the
comparison, which is not greater than 'c' (0xFFFF), so the result
is 'false'.

In C++, c is promoted to 'unsigned int', and thus -2 is also
promoted to 'unsigned int' prior to the comparison, the result of
which (0xFFFF < 0xFFFE) is 'false'.

So C9X and C++ apparently act the same for (A), and use the same
underlying type promotions.


Example 5:
    if (WHITE < -2) ...  // B

In C9X, WHITE is type 'signed int' (because all enum constants are
type 'signed int'), so the result of the comparison to -2 is 'false'.
(WHITE is 0xFFFF, which when converted to 'signed int' is -1, which
is not less than -2.)

In C++, WHITE is promoted to 'unsigned int', and thus the -2 is
promoted to 'unsigned int' (and thus becomes 0xFFFE) prior to the
comparison, which then results (0xFFFF < 0xFFFE) in 'false'.

So C9X and C++ apparently get the same result for (B), but use
different type promotion rules.


Example 6:
    if (WHITE < 0) ...   // C

In C9X, all enum constants are type 'signed int', so WHITE is
converted from 0xFFFF to -1, and the result of the comparison with
0 is 'true'.

In C++, WHITE is converted to 'unsigned int' (the underlying type of
enum Color), so the result of the comparison with 0 is 'false'.

So C9X and C++ apparently get different results for (C), due to
different type promotion rules.


Example 7:
    // Assume that 'int' is 16-bit 2's-compl
    enum Span
    {
        SMALL = 0,
        BIG =   0x7FFF,
        HUGE
    };

In both C9X and C++, the underlying type for enum Span is 'unsigned
int', because the ranges of values exceed the range of 'signed int'.

In C9X, the type of HUGE is 'signed int' (which results in a large
negative value, (signed int)0x8000 => -32768).

In C++, the type of HUGE is 'unsigned int'.

So C9X and C++ apparently get different results for HUGE.


Example 8:
    // Assume that 'int' is 16-bit 2's-compl
    enum Bits
    {
        LEFT =   0x00000001,
        MIDDLE = 0x00004000,
        RIGHT  = 0x00010000
    };

In C9X, the initialization expression for RIGHT is invalid because
it exceeds the range of 'signed int'.  RIGHT, as written, cannot
be used as an enum constant.

In C++, the underlying type for enum Bits is 'signed long int',
because the value of RIGHT exceeds the range of 'signed int' and
'unsigned int'.  RIGHT, when used in an expression, apparently has
the same type as the underlying type of enum Bits, 'signed long int'.

This is a difference between C9X and C++.


Do these examples constitute a fair summary of the situation for
the two languages?

If so, should we issue a defect report for C9X to bring the semantics
of enums more into agreement with C++?

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1999/02/23
Raw View
In article <7asfck$n95$1@nnrp1.dejanews.com>,
  AllanW@my-dejanews.com wrote:
> Neither the final standard nor CD2 have a section 6.7.2.2 or even a
> section 6.7.2. Section 6.7, paragraph 2, talks about initializing
> variables with automatic storage duration.
>
> [ moderator's note: This thread is crossposted to both comp.std.c
>  and comp.std.c++. Section 6.7.2.2 in the C9X draft refers to enums,
>  corresponding to section 6.5.2.2 in the original C standard, and
>  to section 7.2 in the C++ standard. -sdc ]

Yes, I realized that about 5 minutes later, while reading another
note in this same thread.

My comments assumed that we were speaking strictly about C++, and
have nothing to do with C. Sorry if I caused any confusion.

----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@dirac.ceg.uiuc.edu (Siemel Naran)
Date: 1999/02/23
Raw View
On 23 Feb 1999 19:55:49 GMT, Steve Clamage <stephen.clamage@sun.com> wrote:
>sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:

>>#define MAKE_bitenum_operators(Enum,utype) \

>Enum operator|(Enum lhs, Enum rhs) { return Enum( lhs | rhs ); }

The stuff in {...} calls itself recursively

Enum operator|(Enum lhs, Enum rhs)
{
   return Enum( lhs | rhs ); // calls operator|(Enum,Enum)
}


On como, the program just hangs because the function calls itself
forever.  Then I must press Ctrl-C to break.

On egcs, the program calls a segmentation fault because the stack
overflows.


>Enum operator&(Enum lhs, Enum rhs) { return Enum( lhs & rhs ); }
>Enum operator^(Enum lhs, Enum rhs) { return Enum( lhs ^ rhs ); }

Similar remarks.


>An enumerator in an expression is automatically promoted to an
>integer type that depends on its underlying type. (See 4.5 in
>the standard.)

The problem is that since a best match function is available
-- namely operator|(Enum,Enum) -- the conversion from Enum to
integer does not occur.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stanley@West.sun.com (Stanley Friesen [Contractor])
Date: 1999/02/24
Raw View
In article <36D30D32.63C77840@technologist.com>,
David R Tribble  <dtribble@technologist.com> wrote:
>Example 1:
>    // Assume that 'int' is 16-bit 2's-compl
>    enum Color
>    {
>        BLACK = 0x0000,
>        GREY =  0x7FFF,
>        WHITE = 0xFFFF
>    };
> ...
>In C++, all three enum constants are legal, and the underlying type
>for enum Color is 'unsigned int'.  The type of the enum constants
>is also, apparently, 'unsigned int'.
>
Close.  The type of the enum constants is "Color".  Only the underlying
type is specified to be some integral type, in this case 'unsigned int'.
That is, in C++ enumerators belong to the enumeration type for most purposes,
but have the same *representation* as some integral type.

>...
>Assignment (3) is well-defined in both C9X and C++, because c has
>enough bits to hold the value 0x4000.  Assignment (4) is undefined,
>because -1 is out of the range of the underlying type of 'unsigned
>int'.

Unspecified, rather.  The difference is important, as unspecified leaves
less room for odd behavior.
>
>Do these examples constitute a fair summary of the situation for
>the two languages?

Well, I do not know C9X that well as yet, but it seems fiarly close.
>
>If so, should we issue a defect report for C9X to bring the semantics
>of enums more into agreement with C++?
>
I am not sure these need be done, since C9x is still essentially the same
as the prvious C standard.  It was C++ that changed - deliberately, and
for reasons that may not apply to C9X.  Basically, because C++ allows
overloading on user-defined types, it turned out to be very important
that an enum type be a user-defined type in C++.  Most of the differences
follow from that basic change.

So, unless C9X is intended to allow function overloading (multiple
functions with the same name, but different call signatures), I doubt
C9X needs to follow C++ in this regard.

[Basically, in C++ the following are three *different* functions:

    enum Color foo(enum Color c);
    unsigned foo(unsigned u);
    int foo(int i);

without enums as user-defined types, there would at most be two
functions here]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Larry Jones <larry.jones@sdrc.com>
Date: 1999/02/24
Raw View
Clive D.W. Feather wrote:
>
> In article <36CDDCD4.6B33C211@technologist.com>, David R Tribble
> <dtribble@technologist.com> writes
> >
> >I see.  So while all enumeration constants are (signed) int (as
> >per 6.7.2.2), their corresponding enum types may actually be
> >unsigned integers.
>
> Correct.
>
> >This can be a bit confusing.
>
> True. I don't know why it's the case - perhaps Dennis is paying
> attention and can tell us.

Dennis didn't do it -- X3J11 did.  Once X3J11 adopted the "value
preserving" promotion rules, whether an enum type was signed or
unsigned became a moot point because the only unsigned types that
are allowable are types shorter than int (otherwise the constants
wouldn't fit in an int), and they always promote to int when used
in expressions.  And it allows for obvious space savings -- if you
have an enumeration that goes from 0 to 255, why shouldn't it be
stored in an unsigned char instead of a short int?

-Larry Jones

Fortunately, that was our plan from the start. -- Calvin
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1999/02/24
Raw View
David R Tribble wrote:
...
> type of a enum can be 'unsigned int'.  What gives?  How do you
> define an enum type with an underlying type of 'unsigned int' if
> all of the enum constant initialization expressions must be type
> 'signed int'?)

If all of the initialization expressions are 'signed int' expressions
with positive values, then the implementation can choose to use an
unsigned integral type as the underlying type. Note that the developer
has no way of forcing an unsigned underlying type. You can force a
signed type, by including a negative initialization expression.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: AllanW@my-dejanews.com
Date: 1999/02/24
Raw View
In article <36d2bd21.198561155@news.netvision.net.il>,
  zivc@peach-networks.com (Ziv Caspi) wrote:
> (Someone suggested using a MAX_VALUE sentinel in each enumeration.
> This works only if I know in advance that the user is not going to
> define an enumeration larger than the size I picked for MAX_VALUE.)

I believe that someone (it wasn't me) suggested that you set some
enumeration constant (possibly unused) to INT_MAX. This is not at
all the same thing as a MAX_VALUE "sentinel." Your MAX_VALUE, if
used at all, could be far less than INT_MAX.

    enum COLORS { black, brown, red, orange, yellow,
        green, blue, violet, grey, white,
        MAX_VALUE = white, // If you like, makes no difference
        UNUSED_COLOR = INT_MAX };

We only use values black through white (inclusive), so normally 4
bits would be sufficient. However, we told the compiler to allow
values between 0 and INT_MAX. Clearly this won't fit in 4 bits.
We've guaranteed that COLORS is at least as large as an int.

The standard guarantees that enumerations will not be larger than
an int, unless at least one enumeration constant value won't fit
into either an int or an unsigned int. If you specify that color
green is INT_MAX + 10, then there's no way to allow the enumeration
to be the same size as an int. However, if all of the colors do fit
in that range, then we've guaranteed that COLORS is at least as
small as an int.

Therefore, any enumeration which includes INT_MAX but nothing larger
will be the same size as an int.

----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/02/24
Raw View
In article <36D30D32.63C77840@technologist.com>, David R Tribble
<dtribble@technologist.com> writes
>Merging the replies of Clive D.W. Feather in the C (C9X) camp and
>Allan W in the C++ camp, I arrive at some interesting inconsistencies
>between the two languages.  (I'm ignoring C89 here.)

Hmm. See below concerning C89.

>Example 1:
>    // Assume that 'int' is 16-bit 2's-compl
>    enum Color
>    {
>        BLACK = 0x0000,
>        GREY =  0x7FFF,
>        WHITE = 0xFFFF
>    };
>In C9X, all enum constant initialization expressions must be 'signed
>int', so WHITE is apparently initialized to an illegal value.

Right.

>Given only the first two enum constants, enum Color would have an
>underlying type of 'signed int'.

No. It could be unsigned int, or [un]signed long [long], or (since short
must be at least 16 bits) [un]signed short. If chars were 16 bits it
could be char. Or it could be uint25_t. Or ...

>However, Clive's comment that
>initialization expressions must be 'signed int' makes this clearly
>impossible.  Which seems to contradict the rule that the underlying
>type of a enum can be 'unsigned int'.  What gives?

The initialization expressions, and the enumeration constants, have type
signed int. The enumerator type is compatible with *some* integer type
that can hold all the enumeration constants.

>Example 2:
>    // Assume 'enum Color' is 16-bit 'unsigned int'
>    enum Color   c = BLACK;
>    int          i;
>
>    i = c;               // 1A
>    i = BLACK;           // 1B
>    c = (enum Color) i;  // 2
>
>In both C9X and C++, all three assignments are well-defined.

But only because BLACK can be represented in int. In the case of C9X and
int, there's no problem. With i changed to (say) short, there could be.

>Example 3:
>    c = (enum Color) 0x4000;   // 3
>    c = (enum Color) -1;       // 4
>
>Assignment (3) is well-defined in both C9X and C++, because c has
>enough bits to hold the value 0x4000.  Assignment (4) is undefined,
>because -1 is out of the range of the underlying type of 'unsigned
>int'.

No. In C9X, since c is compatible with an unsigned type, the -1 is
converted by adding one more than the maximum value of the type. So it
becomes 0xFFFF in this case.

>Example 6:
>    if (WHITE < 0) ...   // C
>
>In C9X, all enum constants are type 'signed int', so WHITE is
>converted from 0xFFFF to -1, and the result of the comparison with
>0 is 'true'.

Except that WHITE wasn't a valid enum constant, so this would have had a
diagnostic at compile time, so:

>So C9X and C++ apparently get different results for (C), due to
>different type promotion rules.

is wrong.

>Example 7:
>    // Assume that 'int' is 16-bit 2's-compl
>    enum Span
>    {
>        SMALL = 0,
>        BIG =   0x7FFF,
>        HUGE
>    };
>
>In both C9X and C++, the underlying type for enum Span is 'unsigned
>int', because the ranges of values exceed the range of 'signed int'.

Nope; in C9X this would violate a constraint and a diagnostic would be
required (the expression BIG+1, though never actually written, *is* the
expression that defines the value of the enumeration constant and thus
must fit in a signed int).

>Do these examples constitute a fair summary of the situation for
>the two languages?

Other than as I've commented, yes.

The intention of the wording changes in this area of C9X is purely to
clean up ambiguities, though an effect of that has been to change the
promotion rules if the underlying type is unsigned int. We expect that
any sensible C89 implementation would conform to C9X unchanged.

>If so, should we issue a defect report for C9X to bring the semantics
>of enums more into agreement with C++?

No. You should issue a defect report for C++ to bring the semantics of
enums more into agreement with C. Particularly since C was there first.

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: zivc@peach-networks.com (Ziv Caspi)
Date: 1999/02/24
Raw View
On 24 Feb 99 01:14:04 GMT, AllanW@my-dejanews.com wrote:

>I believe that someone (it wasn't me) suggested that you set some
>enumeration constant (possibly unused) to INT_MAX. This is not at
>all the same thing as a MAX_VALUE "sentinel."

I fully understand this. I did not mean MAX_VALUE is the highest
tag used by the enumeration. MAX_VALUE would be INT_MAX if
sized int enumeration is required.

However, this still does not solve the problem:
[...]
>
>The standard guarantees that enumerations will not be larger than
>an int, unless at least one enumeration constant value won't fit
>into either an int or an unsigned int. If you specify that color
>green is INT_MAX + 10, then there's no way to allow the enumeration
>to be the same size as an int.

There lies the problem. While it is very easy for me to tell users of
my code "do not create enumerations whose abosolute value is
larger than MAX_INT", C++ gives me no mechanism to verify that
in a useful manner.

(In theory, since I provide the macros to define enumerations,
I could follow each enumeration declaration with a compile-time
assert that its sizeof is not greater than that of an int. I consider
this an ugly solution.)

(And yes, I *do* realise that most people consider using macros for
most purposes an ugly solution...)

---------------------------------------------
Ziv Caspi
zivca@netvision.net.il


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/02/24
Raw View
In article <7ave4s$829@abyss.West.Sun.COM>, Stanley Friesen [Contractor]
<stanley@West.sun.com> writes
>So, unless C9X is intended to allow function overloading (multiple
>functions with the same name, but different call signatures),

This would require several dead bodies for it to be done over.

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/02/24
Raw View
In article <36D2CCE2.41C67EA6@sdrc.com>, Larry Jones
<larry.jones@sdrc.com> writes
>>>I see.  So while all enumeration constants are (signed) int (as
>>>per 6.7.2.2), their corresponding enum types may actually be
>>>unsigned integers.

>Dennis didn't do it -- X3J11 did.  Once X3J11 adopted the "value
>preserving" promotion rules, whether an enum type was signed or
>unsigned became a moot point because the only unsigned types that
>are allowable are types shorter than int (otherwise the constants
>wouldn't fit in an int), and they always promote to int when used
>in expressions.

Eh ? You're back to front. Since all nonnegative signed ints can fit in
an unsigned int, the enumeration type *could* be compatible with
unsigned int. Of course, the "promotion" to signed int in C89 would not
change the value.

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stanley@West.sun.com (Stanley Friesen [Contractor])
Date: 1999/02/24
Raw View
In article <GLJ4GeAO1902Eww2@on-the-train.demon.co.uk>,
Clive D.W. Feather <clive@demon.net> wrote:
>No. You should issue a defect report for C++ to bring the semantics of
>enums more into agreement with C. Particularly since C was there first.

Except it isn't a defect in C++.  The changes were deliberate, in order
to integrate enumerations into the overall C++ type system better,
especially with regard to overloading and type-safe linking.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <dtribble@technologist.com>
Date: 1999/02/19
Raw View
Clive D.W. Feather wrote:
>>>
>>[elided]
>>> enum foo is the enumeration type. It is compatible with some integer
>>> type T; there is no portable way to know what T is, but all the
>>> foo_x have values that can be represented in T.

David R Tribble wrote:
>> Is the following not portable?:
>>
>>     if (sizeof(enum foo) == sizeof(signed char))
>>         ... // enum foo is the same size as signed char
>>     else if (sizeof(enum foo) == sizeof(signed short))
>>         ... // enum foo is the same size as signed short
>>     else if (sizeof(enum foo) == sizeof(signed int))
>>         ... // enum foo is the same size as signed int
>>     else if (sizeof(enum foo) == sizeof(signed long))
>>         ... // enum foo is the same size as signed long
>>     else if (sizeof(enum foo) == sizeof(signed long long))
>>         ... // enum foo is the same size as signed long long
>>     else
>>         ... // enum foo is the size of a non-standard integer type

James Kuyper wrote:
> This leaves unspecified what the signedness of the type is, and
> therefore doesn't tell us the range of permitted values.

If I read the C9X and C++ specs correctly, enum types are always
signed integers.

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/02/19
Raw View
David R Tribble <dtribble@technologist.com> writes:

>David R Tribble wrote:
>>> Is the following not portable?:
>>>
>>>     if (sizeof(enum foo) == sizeof(signed char))
>>>         ... // enum foo is the same size as signed char
>>>     else if (sizeof(enum foo) == sizeof(signed short))
>>>         ... // enum foo is the same size as signed short
>>>     else if (sizeof(enum foo) == sizeof(signed int))
>>>         ... // enum foo is the same size as signed int
>>>     else if (sizeof(enum foo) == sizeof(signed long))
>>>         ... // enum foo is the same size as signed long
>>>     else if (sizeof(enum foo) == sizeof(signed long long))
>>>         ... // enum foo is the same size as signed long long
>>>     else
>>>         ... // enum foo is the size of a non-standard integer type

>James Kuyper wrote:
>> This leaves unspecified what the signedness of the type is, and
>> therefore doesn't tell us the range of permitted values.

>If I read the C9X and C++ specs correctly, enum types are always
>signed integers.

In C89 and C9X, all enumerator values must be representable as type
int, and enumerators have type int in an expression. The
implementation can choose some other type to represent an enumeration
type, as long as that type can represent all the enumerator values.

I'm surprised that C9X doesn't allow enums with long or long long
values.  I always assumed that was an oversight in C89.  Maybe
someone can explain why the restriction is still present.

As far as I can tell, neither C89 nor C9X defines what happens
if you attempt to create a value of enumeration type that does
not correspond to one of the enumerator values.
 /* C example */
 enum E { e0, e1=5 };
 enum E s = (enum E)4;   // undefined result?
 enum E l = (enum E)129; // undefined result?
If I'm correct, the representable range is not relevant, since no
standard-conforming program can make use of other values.

In C++, the "underlying type" of the enum must be capable of
representing all the values of the enumerators, but can be signed
or unsigned.  Refer to 7.2 paragraph 5 in the C++ standard.

But the range that can be represented by the underlying type is
still not directly relevant. From the declaration of the enum
type, you compute the number of bits necessary to represent the
range of the declared values. (Unless a negative enumerator is
specified, that range is non-negative.) Any value that can be
represented in that number of bits can be converted to that
enum type. Attempting to convert a value outside that range
(which is not necessarily as large as the range of the underlying
type) has undefined results.  Refer to 7.2 paragraph 6 in the C++
standard.
 // C++ example
 enum E { e0, e1=5 };
 E s = (E)4;   // well-defined
 E m = (E)6;   // undefined result
 E l = (E)129; // undefined result

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/02/19
Raw View
In article <7aid2l$ig4$1@engnews1.eng.sun.com>, Steve Clamage
<clamage@Eng.Sun.COM> writes
>I'm surprised that C9X doesn't allow enums with long or long long
>values.  I always assumed that was an oversight in C89.  Maybe
>someone can explain why the restriction is still present.

No request was made to change this. It may be because, in C89,
enumerated types promoted to int under all circumstances. [In C9X
enumerated types promote in the same way as their compatible type does.]

>As far as I can tell, neither C89 nor C9X defines what happens
>if you attempt to create a value of enumeration type that does
>not correspond to one of the enumerator values.
>       /* C example */
>       enum E { e0, e1=5 };
>       enum E s = (enum E)4;   // undefined result?
>       enum E l = (enum E)129; // undefined result?

This was addressed in a DR. The behaviour is the same as if you replaced
"enum E" by a compatible type. So the initialization of s is guaranteed
to work; that of l might be undefined because the compatible type might
be signed char.

>But the range that can be represented by the underlying type is
>still not directly relevant.

Wrong (at least in C).

>From the declaration of the enum
>type, you compute the number of bits necessary to represent the
>range of the declared values.
[...]

Wrong in C.

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/02/19
Raw View
In article <7aid2l$ig4$1@engnews1.eng.sun.com>,
  clamage@Eng.Sun.COM (Steve Clamage) wrote:
> In C++, the "underlying type" of the enum must be capable of
> representing all the values of the enumerators, but can be signed
> or unsigned.  Refer to 7.2 paragraph 5 in the C++ standard.
>
> But the range that can be represented by the underlying type is
> still not directly relevant. From the declaration of the enum
> type, you compute the number of bits necessary to represent the
> range of the declared values. (Unless a negative enumerator is
> specified, that range is non-negative.) Any value that can be
> represented in that number of bits can be converted to that
> enum type. Attempting to convert a value outside that range
> (which is not necessarily as large as the range of the underlying
> type) has undefined results.  Refer to 7.2 paragraph 6 in the C++
> standard.
>  // C++ example
>  enum E { e0, e1=5 };
>  E s = (E)4;   // well-defined
>  E m = (E)6;   // undefined result

You mean defined here, don't you?  One of the enum values is 5, which
requires 3 bits to represent, and 6 can also be represented in three
bits.  (Or did you mean to use -6 as the example?)

>  E l = (E)129; // undefined result

--
James Kanze                                           GABI Software, S   rl
Conseils en informatique orient    objet  --
                          --  Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr          mailto: James.Kanze@dresdner-bank.com

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Larry Jones <larry.jones@sdrc.com>
Date: 1999/02/19
Raw View
David R Tribble wrote:
>
> If I read the C9X and C++ specs correctly, enum types are always
> signed integers.

I can't speak for C++, but C9X certainly allows enum types to be either
signed or unsigned.

-Larry Jones

I can do that!  It's a free country!  I've got my rights! -- Calvin
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/02/19
Raw View
In article <36CCA79A.A2522A94@technologist.com>, David R Tribble
<dtribble@technologist.com> writes
>If I read the C9X and C++ specs correctly, enum types are always
>signed integers.

You don't: in C9X, if all the enumeration constants are nonnegative then
the type can be unsigned.

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@West.sun.com (Stanley Friesen [Contractor])
Date: 1999/02/19
Raw View
In article <7aid2l$ig4$1@engnews1.eng.sun.com>,
Steve Clamage <clamage@Eng.Sun.COM> wrote:
>But the range that can be represented by the underlying type is
>still not directly relevant. From the declaration of the enum
>type, you compute the number of bits necessary to represent the
>range of the declared values. (Unless a negative enumerator is
>specified, that range is non-negative.) Any value that can be
>represented in that number of bits can be converted to that
>enum type. Attempting to convert a value outside that range
>(which is not necessarily as large as the range of the underlying
>type) has undefined results.  Refer to 7.2 paragraph 6 in the C++
>standard.

Undefined or unspecified?  I would have thought the latter.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/02/20
Raw View
On 19 Feb 99 14:10:00 GMT, Steve Clamage <clamage@Eng.Sun.COM> wrote:

>In C++, the "underlying type" of the enum must be capable of
>representing all the values of the enumerators, but can be signed
>or unsigned.  Refer to 7.2 paragraph 5 in the C++ standard.

What if the underlying type required is too big?  Eg,
   enum E { e=0xffffffffffffffffffffffffffffff; };
This may require a "long long long long long" or something like that.
This case arises in practice when we have many many bit fields.  Eg,
a "long long" might have space for only 64 bit fields, and the
implementation does not have a "long long long".

I was thinking maybe we could use a std::bitset, but this sounds a
little overboard.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/02/20
Raw View
David R Tribble <dtribble@technologist.com> writes
>> If I read the C9X and C++ specs correctly, enum types are always
>> signed integers.

"Clive D.W. Feather" wrote:
> You don't: in C9X, if all the enumeration constants are nonnegative
> then the type can be unsigned.

I see.  So while all enumeration constants are (signed) int (as
per 6.7.2.2), their corresponding enum types may actually be
unsigned integers.

This can be a bit confusing.

It also raises a question: Does a variable of an enum type, that is
represented by an underlying unsigned integer type, get converted
into a signed or unsigned int when it is used in an expression?

    enum Color
    {   // assumed to have 'unsigned int' 2's-compl representation
        BLACK = 0x0000,
        RED =   0x0111,
        GREEN = 0x0222,
        BLUE =  0x0444,
        GRAY =  0x7FFF,
        ...
        WHITE = 0xFFFF
    };

    enum Color  c = WHITE;
    int         i;    // assumed to be 16-bit

    if (c < -2)       // true or false?
        ...

Which of these happens?:

1. 'c' is 'unsigned int', which is converted to 'signed int'
 (0xFFFF => -1), which compares greater than (signed) '-1',
 resulting in 'false'.

2. 'c' is 'unsigned int', which causes the '-2' to be cast to
 'unsigned int' (-2 => 0xFFFE) prior to the comparison, which is
 less than 'c' (0xFFFF), resulting in 'true'.

My initial reading of 6.3.1.1 and 6.3.1.8 leads me to believe
that (2) is what happens.

In contrast, the following statement is false (using the same
assumptions about size as the example above):

    if (WHITE < -2) ...  // false

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/02/20
Raw View
"Clive D.W. Feather" <clive@on-the-train.demon.co.uk> writes:

>In article <7aid2l$ig4$1@engnews1.eng.sun.com>, Steve Clamage
><clamage@Eng.Sun.COM> writes

>>But the range that can be represented by the underlying type is
>>still not directly relevant.

>Wrong (at least in C).

>>From the declaration of the enum
>>type, you compute the number of bits necessary to represent the
>>range of the declared values.
>[...]

>Wrong in C.

Both of those comments were in the part of my article that
addresses C++ specifically. I thought I made that clear.
Evidently I didn't.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/02/20
Raw View
Correcting some errors that were pointed out by others:

clamage@Eng.Sun.COM (Steve Clamage) writes:

In C++:
>... the range that can be represented by the underlying type is
>still not directly relevant. From the declaration of the enum
>type, you compute the number of bits necessary to represent the
>range of the declared values. (Unless a negative enumerator is
>specified, that range is non-negative.) Any value that can be
>represented in that number of bits can be converted to that
>enum type. Attempting to convert a value outside that range
>(which is not necessarily as large as the range of the underlying
>type) has undefined results.  Refer to 7.2 paragraph 6 in the C++
>standard.
> // C++ example
> enum E { e0, e1=5 };
> E s = (E)4;   // well-defined
> E m = (E)6;   // undefined result
> E l = (E)129; // undefined result

I should have said "unspecified" each place I said "undefined".

The initialization of m is well-defined, since the value 5 requires
3 bits and so does the value 6.  Any value outside the range
0-8 would have unspecified results.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/02/20
Raw View
sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:

>On 19 Feb 99 14:10:00 GMT, Steve Clamage <clamage@Eng.Sun.COM> wrote:

>>In C++, the "underlying type" of the enum must be capable of
>>representing all the values of the enumerators, but can be signed
>>or unsigned.  Refer to 7.2 paragraph 5 in the C++ standard.

>What if the underlying type required is too big?  Eg,
>   enum E { e=0xffffffffffffffffffffffffffffff; };

Still speaking about C++, that can't happen. If an integer literal
cannot be represented as one of the fundamental integer types, the
behavior of the program is undefined. (2.1.3.1 paragraph 2). You
cannot expect to create enum type E or enumerator e unless the
implementation has a 120-bit integer type. (Trying to create
the value via an arithmetic expression won't work either, since
it bumps into the overflow rules.)

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/02/21
Raw View
In article <36CDDCD4.6B33C211@technologist.com>, David R Tribble
<dtribble@technologist.com> writes
>"Clive D.W. Feather" wrote:

Why the quotes ? It's my real name.

>> You don't: in C9X, if all the enumeration constants are nonnegative
>> then the type can be unsigned.
>I see.  So while all enumeration constants are (signed) int (as
>per 6.7.2.2), their corresponding enum types may actually be
>unsigned integers.

Correct.

>This can be a bit confusing.

True. I don't know why it's the case - perhaps Dennis is paying
attention and can tell us.

>It also raises a question: Does a variable of an enum type, that is
>represented by an underlying unsigned integer type, get converted
>into a signed or unsigned int when it is used in an expression?

Yes.

In C89 it's converted to signed int, which has some very peculiar
effects if it was already bigger. In C9X it behaves just like the type
it's compatible with.

>    enum Color
>    {   // assumed to have 'unsigned int' 2's-compl representation
[...]
>        WHITE = 0xFFFF
>    };
>
>    enum Color  c = WHITE;
>    int         i;    // assumed to be 16-bit

If int is 16 bits, WHITE is not a valid enumeration constant.

>1. 'c' is 'unsigned int', which is converted to 'signed int'

In C89, yes. What then happens is your guess (it's implementation-
defined).

>2. 'c' is 'unsigned int', which causes the '-2' to be cast to
> 'unsigned int' (-2 => 0xFFFE) prior to the comparison, which is
> less than 'c' (0xFFFF), resulting in 'true'.

In C9X, yes.

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1999/02/21
Raw View
In article <7amtev$s6b$1@engnews1.eng.sun.com>, Steve Clamage
<stephen.clamage@sun.com> writes
>>What if the underlying type required is too big?  Eg,
>>   enum E { e=0xffffffffffffffffffffffffffffff; };
>
>Still speaking about C++, that can't happen.

Nor in C - the value after the = must fit into the type signed int.

--
Clive D.W. Feather    | Director of            | Work: <clive@demon.net>
Tel: +44 181 371 1138 |   Software Development | Home: <clive@davros.org>
Fax: +44 181 371 1037 | Demon Internet Ltd.    | Web:  <http://www.davros.org>
Written on my laptop; please observe the Reply-To address
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: zivc@peach-networks.com (Ziv Caspi)
Date: 1999/02/22
Raw View
On 19 Feb 99 14:10:00 GMT, clamage@Eng.Sun.COM (Steve Clamage) wrote:
[...]
>
>In C89 and C9X, all enumerator values must be representable as type
>int, and enumerators have type int in an expression. The
>implementation can choose some other type to represent an enumeration
>type, as long as that type can represent all the enumerator values.
>
>I'm surprised that C9X doesn't allow enums with long or long long
>values.  I always assumed that was an oversight in C89.  Maybe
>someone can explain why the restriction is still present.

If I could sneak in a related question -- Why doesn't C++ allow the
programmer to specify the underlying type? (Something like
"enum E : int { ... };")

(I have a multitude of nifty macros to manipulate enumerations, and
they all assume that "sizeof enum whatever == sizeof int"; I wish
there was a portable way to move them to C++.)

[...]

---------------------------------------------
Ziv Caspi
zivca@netvision.net.il
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: AllanW@my-dejanews.com
Date: 1999/02/22
Raw View
In article <36CDDCD4.6B33C211@technologist.com>,
  David R Tribble <dtribble@technologist.com> wrote:
> >> If I read the C9X and C++ specs correctly, enum types are always
> >> signed integers.
>
> "Clive D.W. Feather" wrote:
> > You don't: in C9X, if all the enumeration constants are nonnegative
> > then the type can be unsigned.
>
> I see.  So while all enumeration constants are (signed) int (as
> per 6.7.2.2), their corresponding enum types may actually be
> unsigned integers.

Neither the final standard nor CD2 have a section 6.7.2.2 or even a
section 6.7.2. Section 6.7, paragraph 2, talks about initializing
variables with automatic storage duration.

[ moderator's note: This thread is crossposted to both comp.std.c
 and comp.std.c++. Section 6.7.2.2 in the C9X draft refers to enums,
 corresponding to section 6.5.2.2 in the original C standard, and
 to section 7.2 in the C++ standard. -sdc ]

I couldn't find anything suggesting that all enumeration constants
are signed int. I did find this in 7.2 p1:

  The identifiers in an enumerator-list are declared as  constants, and
  can  appear wherever constants are required.  An enumerator-definition
  with = gives  the  associated enumerator  the value indicated by the
  constant-expression. The constant-expression shall be of integral or
  enumeration type. If the first enumerator has no initializer, the value
  of the corresponding constant is zero. An enumerator-definition without
  an initializer gives the enumerator the value obtained by increasing
  the value of the previous enumerator by one.

The corresponding text in CD2 is also in 7.2 p2:

  The identifiers in an enumerator-list are declared as  constants,  and
  can  appear wherever constants are required.  If no enumerator-defini-
  tions with = appear, then the values of  the  corresponding  constants
  begin  at zero and increase by one as the enumerator-list is read from
  left to right.  An enumerator-definition with = gives  the  associated
  enumerator  the value indicated by the constant-expression; subsequent
  enumerators without initializers continue  the  progression  from  the
  assigned  value.  The constant-expression shall be of integral or enu-
  meration type.

> This can be a bit confusing.
>
> It also raises a question: Does a variable of an enum type, that is
> represented by an underlying unsigned integer type, get converted
> into a signed or unsigned int when it is used in an expression?

7.2 p8 states that "the value of an enumerator or an object of an
enumeration type is converted to AN INTEGER by integral promotion"
(emphasis mine). Notice that this does not say it is converted to
an int. By my reading, enumerator constants are converted to some
unspecified integer type.

Paragraphs 5 and 6 describe an enumeration's underlying type in
great detail as "an integral type that can represent all the
enumerator values defined in the enumeration." Why? One reason is
to make clear what values an enumeration can hold, other than the
values in enumeration constants, i.e.
    enum color { red, yellow, green=20, blue };
    color col = color(10);
is legal because color must have at least 5 bits to hold all the
enumeration constants, and 5 bits is sufficient to hold the value
10. But given that an enumeration must have an underlying type, I
would expect that the vast majority of compilers would promote
enumeration constants to the enumeration's underlying type. Thus,
enumeration constants are converted to some type of signed
integers if ANY of the enumeration constants for that enumeration
are negative.

>     enum Color
>     {   // assumed to have 'unsigned int' 2's-compl representation
>         BLACK = 0x0000,
>         RED =   0x0111,
>         GREEN = 0x0222,
>         BLUE =  0x0444,
>         GRAY =  0x7FFF,
>         ...
>         WHITE = 0xFFFF
>     };

These are all unsigned. "It is implementation-defined which integral
type is used as the underlying type for an enumeration, except that
the underlying type shall not be larger than int unless the value
of an enumerator cannot fit in an int or unsigned int." If the
compiler uses 16-bit int and 16-bit unsigned int, then the underlying
type probably has to be unsigned int.

>     enum Color  c = WHITE;
>     int         i;    // assumed to be 16-bit
>
>     if (c < -2)       // true or false?
>         ...
>
> Which of these happens?:
>
> 1. 'c' is 'unsigned int', which is converted to 'signed int'
>  (0xFFFF => -1), which compares greater than (signed) '-1',
>  resulting in 'false'.
>
> 2. 'c' is 'unsigned int', which causes the '-2' to be cast to
>  'unsigned int' (-2 => 0xFFFE) prior to the comparison, which is
>  less than 'c' (0xFFFF), resulting in 'true'.
>
> My initial reading of 6.3.1.1 and 6.3.1.8 leads me to believe
> that (2) is what happens.

Shouldn't work that way, no.

c is promoted to unsigned int. Since we compare an unsigned int with
a signed int, the -2 is promoted to an unsigned int (5 p9).
0xFFFF<0xFFFE is false.

> In contrast, the following statement is false (using the same
> assumptions about size as the example above):
>
>     if (WHITE < -2) ...  // false

Promote WHITE to unsigned int, and -2 to unsigned int.
0xFFFF<0xFFFE is still false.

----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1999/02/22
Raw View
In article <7amtqu$sle$1@engnews1.eng.sun.com>,
  clamage@Eng.Sun.COM (Steve Clamage) wrote:
> Correcting some errors that were pointed out by others:
>
> clamage@Eng.Sun.COM (Steve Clamage) writes:
>
> In C++:
> >... the range that can be represented by the underlying type is
> >still not directly relevant. From the declaration of the enum
> >type, you compute the number of bits necessary to represent the
> >range of the declared values. (Unless a negative enumerator is
> >specified, that range is non-negative.) Any value that can be
> >represented in that number of bits can be converted to that
> >enum type. Attempting to convert a value outside that range
> >(which is not necessarily as large as the range of the underlying
> >type) has undefined results.  Refer to 7.2 paragraph 6 in the C++
> >standard.
> > // C++ example
> > enum E { e0, e1=5 };
> > E s = (E)4;   // well-defined
> > E m = (E)6;   // undefined result
> > E l = (E)129; // undefined result
>
> I should have said "unspecified" each place I said "undefined".
>
> The initialization of m is well-defined, since the value 5 requires
> 3 bits and so does the value 6.  Any value outside the range
> 0-8 would have unspecified results.

Any value outside the range 0-7 would have unspecified results.
The value 8 requires 4 bits: in binary it is 1000.

----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
Date: 1999/02/22
Raw View
zivc@peach-networks.com (Ziv Caspi) writes:

|> (I have a multitude of nifty macros to manipulate enumerations, and
|> they all assume that "sizeof enum whatever == sizeof int"; I wish
|> there was a portable way to move them to C++.)

Add an entry with value INT_MAX to the enum definition.

--
Andreas Schwab                                      "And now for something
schwab@issan.cs.uni-dortmund.de                      completely different"
schwab@gnu.org
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: msherman@magma.ca (Marc Sherman)
Date: 1999/02/22
Raw View
In article <36d03430.32434237@news.netvision.net.il>,
Ziv Caspi <zivc@peach-networks.com> wrote:
>If I could sneak in a related question -- Why doesn't C++ allow the
>programmer to specify the underlying type? (Something like
>"enum E : int { ... };")
>
>(I have a multitude of nifty macros to manipulate enumerations, and
>they all assume that "sizeof enum whatever == sizeof int"; I wish
>there was a portable way to move them to C++.)

You can do this using templates and partial specialization:

template <class TEnum, size_t TSize> void EnumBitFiddlerImpl(TEnum& e);
template <class TEnum> void EnumBitFiddlerImpl<1>(TEnum& e)
{ /* implement version for char-based enum */ }
// repeat for other sizes
template <class TEnum> void EnumBitFiddler(TEnum& e)
{ EnumBitFiddlerImpl<sizeof(e)>(e); }

If you need to specialize your implementation for signed and unsigned
underlying types as well, add a bool TSigned template parameter to the
top template, and init it in the bottom function implementation with
(((TEnum)-1) < ((TEnum)0)).

- Marc
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]