Help with bit-field semantics in C and C++

Gabriel Dos Reis gdr@integrable-solutions.net
Tue Aug 24 20:47:00 GMT 2004


Mike Stump <mrs@apple.com> writes:

| On Tuesday, August 24, 2004, at 12:32  PM, Gabriel Dos Reis wrote:
| 
| > Mike Stump <mrs@apple.com> writes:
| >
| > | On Tuesday, August 24, 2004, at 10:51  AM, Joe Buck wrote:
| > | > On Tue, Aug 24, 2004 at 11:05:41AM -0600, Roger Sayle wrote:
| > | >> The problem here is that a C++ enum can hold values outside the
| > range
| > | >> of it's type.
| > |
| > | > If it does, the program is not a valid ISO C++ program.
| > |
| > | ?  What?  Of course it is.
| > |
| > | I think the standard is perfectly clear in this area:
| >
| > You're quoting C99 which has a quite different semantics in this area.
| > Joe is talking about C++.
| 
| While C++ is a times slightly different from C...  It isn't all that
| different:
| 
| 7 A value of integral type can be explicitly converted to an enumeration
|    type.  The value is unchanged if the  integral  value  is  within  the
|    range  of the enumeration values (_dcl.enum_).  Otherwise, the result-
|    ing enumeration value is unspecified.

Let's see the example at hand.

   enum E { zero = 0x00, one = 0x01 };

   void test(int n)
   {
     enum E x;

     x = (E)n;
     switch (x)
     {
     case zero:  foo();  break;
     case one:   bar();  break;
     }
   }

   int main()
   {
     test(255);
     return 0;
   }


The underlying type of E needs only be an integer type large enough to
contain a data expressible with a single bit -- this is where C
differs from C++ on the issue. E.g. That integer type needs
representing only two distinc values. That is, using bool is quite a fair.

| 4 Each enumeration defines a type  that  is  different  from  all  other
|    types.  Following the closing brace of an enum-specifier, each enumer-
|    ator has the type of its enumeration.  Prior to the closing brace, the
|    type  of each enumerator is the type of its initializing value.  If an
|    initializer is specified for an enumerator, the initializing value has
|    the  same  type as the expression.  If no initializer is specified for
|    the first enumerator, the type is an unspecified integral type.   Oth-
|    erwise  the  type is the same as the type of the initializing value of
|    the preceding enumerator unless the incremented value  is  not  repre-
|    sentable  in that type, in which case the type is an unspecified inte-
|    gral type sufficient to contain the incremented value.
| 
| 5 The underlying type of an enumeration is an  integral  type  that  can
|    represent all the enumerator values defined in the enumeration.  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 enumerator-list is empty, the underlying type
|    is as if the enumeration had a single enumerator with  value  0.   The
|    value of sizeof() applied to an enumeration type, an object of enumer-
|    ation type, or an enumerator, is the value of sizeof() applied to  the
|    underlying type.

The bits of the standard text the most relevant to Roger's question are

        http://gcc.gnu.org/ml/gcc/2004-08/msg01167.html

Those say that the sequence of statements

     enum E x;

     x = (E)n;

store an unspecified value in the location designated by x.  It may be
0 or 1 or whatever fits, it does not matter.

| This does not make the code _not_ C++.  My contention remains, calling
| the code not C++ is wrong and misleading.

Probably _not_ C++ is a bit strong, but this is not the code that we
should worry about when optimizing.  Those deserve what they get.

-- Gaby



More information about the Gcc mailing list