Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #150254 > unrolled thread

clarification about enums in C

Started byThiago Adams <thiago.adams@gmail.com>
First post2020-02-25 15:38 -0800
Last post2020-02-26 21:04 +0000
Articles 20 on this page of 31 — 7 participants

Back to article view | Back to comp.lang.c


Contents

  clarification about enums in C Thiago Adams <thiago.adams@gmail.com> - 2020-02-25 15:38 -0800
    Re: clarification about enums in C luser droog <luser.droog@gmail.com> - 2020-02-25 19:19 -0800
    Re: clarification about enums in C James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-02-25 21:17 -0800
      Re: clarification about enums in C Thiago Adams <thiago.adams@gmail.com> - 2020-02-27 04:01 -0800
    Re: clarification about enums in C David Brown <david.brown@hesbynett.no> - 2020-02-26 11:29 +0100
      Re: clarification about enums in C already5chosen@yahoo.com - 2020-02-26 14:05 -0800
        Re: clarification about enums in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2020-02-26 23:03 +0000
          Re: clarification about enums in C already5chosen@yahoo.com - 2020-02-26 23:29 -0800
            Re: clarification about enums in C already5chosen@yahoo.com - 2020-02-27 01:42 -0800
              Re: clarification about enums in C David Brown <david.brown@hesbynett.no> - 2020-02-27 11:02 +0100
                Re: clarification about enums in C Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-02-27 06:37 -0800
                  Re: clarification about enums in C David Brown <david.brown@hesbynett.no> - 2020-02-27 16:18 +0100
                    Re: clarification about enums in C James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-02-27 23:24 -0500
        Re: clarification about enums in C David Brown <david.brown@hesbynett.no> - 2020-02-27 09:50 +0100
          Re: clarification about enums in C Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-02-27 06:33 -0800
            Re: clarification about enums in C already5chosen@yahoo.com - 2020-02-27 06:53 -0800
            Re: clarification about enums in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2020-02-27 15:05 +0000
            Re: clarification about enums in C David Brown <david.brown@hesbynett.no> - 2020-02-27 16:24 +0100
            Re: clarification about enums in C Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-02-28 01:27 -0800
        Re: clarification about enums in C already5chosen@yahoo.com - 2020-02-27 01:29 -0800
          Re: clarification about enums in C David Brown <david.brown@hesbynett.no> - 2020-02-27 11:12 +0100
            Re: clarification about enums in C already5chosen@yahoo.com - 2020-02-27 03:09 -0800
              Re: clarification about enums in C David Brown <david.brown@hesbynett.no> - 2020-02-27 14:33 +0100
                Re: clarification about enums in C already5chosen@yahoo.com - 2020-02-27 05:44 -0800
                  Re: clarification about enums in C David Brown <david.brown@hesbynett.no> - 2020-02-27 14:57 +0100
          Re: clarification about enums in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2020-02-27 11:53 +0000
            Re: clarification about enums in C James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-02-27 23:52 -0500
              Re: clarification about enums in C Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-02-28 01:30 -0800
    Re: clarification about enums in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2020-02-26 14:09 +0000
      Re: clarification about enums in C Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-02-26 09:47 -0800
        Re: clarification about enums in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2020-02-26 21:04 +0000

Page 1 of 2  [1] 2  Next page →


#150254 — clarification about enums in C

FromThiago Adams <thiago.adams@gmail.com>
Date2020-02-25 15:38 -0800
Subjectclarification about enums in C
Message-ID<aaf0f57f-4ae1-4c4a-a0aa-314eade48440@googlegroups.com>
From the standard:

"The identifiers in an enumerator list are declared as constants 
that have type int and may appear wherever such are permitted.127)"

But there is a foot note:

"Each enumerated type shall be compatible with char, a signed 
integer type, or an unsigned integer type. The choice of type 
is implementation-defined,128)"

"128) An implementation may delay the choice of which integer 
type until all enumeration constants have been seen."

I am confused. 

enum E { A, B};

Can A and B be int and E not int?
Can A B and E be != int? 

If so, what is this 

"The identifiers in an enumerator list are declared as constants 
that have type int and may appear wherever such are permitted.127)"

[toc] | [next] | [standalone]


#150258

Fromluser droog <luser.droog@gmail.com>
Date2020-02-25 19:19 -0800
Message-ID<3c3d49d5-e488-4c36-b73b-87de4eb9d032@googlegroups.com>
In reply to#150254
On Tuesday, February 25, 2020 at 5:38:47 PM UTC-6, Thiago Adams wrote:
> From the standard:
> 
> "The identifiers in an enumerator list are declared as constants 
> that have type int and may appear wherever such are permitted.127)"
> 
> But there is a foot note:
> 
> "Each enumerated type shall be compatible with char, a signed 
> integer type, or an unsigned integer type. The choice of type 
> is implementation-defined,128)"
> 
> "128) An implementation may delay the choice of which integer 
> type until all enumeration constants have been seen."
> 
> I am confused. 
> 
> enum E { A, B};
> 
> Can A and B be int and E not int?
> Can A B and E be != int? 
> 
> If so, what is this 
> 
> "The identifiers in an enumerator list are declared as constants 
> that have type int and may appear wherever such are permitted.127)"

It's talking about declaring a enum variable.

  enum E myenum;

What type is 'myenum'? It might seem obvious to implement as the
same as an int. But in the your example, having only two names A and B,
that could comfortable fit in a signed char. So the compiler is
given leeway to choose the *underlying* type. The names A and B yield
int in an expression, but in most expressions the promotion rules
would probably convert it to int anyway, ie. even if it were to yield a
signed char sometimes.

[toc] | [prev] | [next] | [standalone]


#150259

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2020-02-25 21:17 -0800
Message-ID<545cdc9b-e091-4584-9ccf-dbe915d60f03@googlegroups.com>
In reply to#150254
On Tuesday, February 25, 2020 at 6:38:47 PM UTC-5, Thiago Adams wrote:
> From the standard:
> 
> "The identifiers in an enumerator list are declared as constants 
> that have type int and may appear wherever such are permitted.127)"

That's from 6.7.2.2p3.

> But there is a foot note:
> 
> "Each enumerated type shall be compatible with char, a signed 
> integer type, or an unsigned integer type. The choice of type 
> is implementation-defined,128)"

That is NOT a footnote. It's 6.7.2.2p4. The "127)" and "128)" that appear in those citations refer to actual footnotes.

> "128) An implementation may delay the choice of which integer 
> type until all enumeration constants have been seen."
> 
> I am confused. 
> 
> enum E { A, B};
> 
> Can A and B be int and E not int?
> Can A B and E be != int?

A and B are enumeration constants, and are required, by the clause that you've cited, to have the type int. "Can" doesn't enter into the matter.
E is a tag for an enumerated type. "enum E" designates that type. The implementation must choose an integer type that enum E is compatible with, but enum E does not itself designate that type. The integer type that it's compatible with doesn't have to be "int", though it can be.

> If so, what is this 
> 
> "The identifiers in an enumerator list are declared as constants 
> that have type int and may appear wherever such are permitted.127)"

That is the statement which specifies that A and B have the type int.

I suspect that those answers will still leave you confused. It might help if you were more specific about how they confuse you. In particular, what ideas do you have that are in conflict with those specifications?

[toc] | [prev] | [next] | [standalone]


#150291

FromThiago Adams <thiago.adams@gmail.com>
Date2020-02-27 04:01 -0800
Message-ID<496af4c2-b2e8-4d54-bded-bd4087aa1a90@googlegroups.com>
In reply to#150259
On Wednesday, February 26, 2020 at 2:17:52 AM UTC-3, James Kuyper wrote:
> On Tuesday, February 25, 2020 at 6:38:47 PM UTC-5, Thiago Adams wrote:
> > From the standard:
> > 
> > "The identifiers in an enumerator list are declared as constants 
> > that have type int and may appear wherever such are permitted.127)"
> 
> That's from 6.7.2.2p3.
> 
> > But there is a foot note:
> > 
> > "Each enumerated type shall be compatible with char, a signed 
> > integer type, or an unsigned integer type. The choice of type 
> > is implementation-defined,128)"
> 
> That is NOT a footnote. It's 6.7.2.2p4. The "127)" and "128)" that appear in those citations refer to actual footnotes.
> 
> > "128) An implementation may delay the choice of which integer 
> > type until all enumeration constants have been seen."
> > 
> > I am confused. 
> > 
> > enum E { A, B};
> > 
> > Can A and B be int and E not int?
> > Can A B and E be != int?
> 
> A and B are enumeration constants, and are required, by the clause that you've cited, to have the type int. "Can" doesn't enter into the matter.
> E is a tag for an enumerated type. "enum E" designates that type. The implementation must choose an integer type that enum E is compatible with, but enum E does not itself designate that type. The integer type that it's compatible with doesn't have to be "int", though it can be.
> 
> > If so, what is this 
> > 
> > "The identifiers in an enumerator list are declared as constants 
> > that have type int and may appear wherever such are permitted.127)"
> 
> That is the statement which specifies that A and B have the type int.
> 
> I suspect that those answers will still leave you confused. It might help if you were more specific about how they confuse you. In particular, what ideas do you have that are in conflict with those specifications?

Thanks everyone for the answers.
It is clear now, what the standard says about enumeration constants 
and enum type.

Considering that compilers also support unsigned long long for 
constants I think the standard should be updated.

For instance:

#include <stdio.h>

enum E {
    A = -1,
    B = 0xFFFFFFFFFFFF
};

int main() {
    enum E e = A;
    printf("%d %d %d", (int)sizeof e, (int)sizeof A, (int)sizeof(B));
}

It prints:
8 4 8

What is interesting here is that A is 4 and B is 8.

The specification should say that one enumeration constant is
an integer big enough to hold the value of the expression or
int by default.
And the enum type is a type big enough to hold all the enumeration
constants.

And surprise.. if we compile the same program in C++.

#include <stdio.h>

enum E {
    A = -1,
    B = 0xFFFFFFFFFFFF
};

int main()
{
    enum E e = A;
    printf("%d %d %d", (int)sizeof e, (int)sizeof A, (int)sizeof(B));
}
 
it prints:

8 8 8 

I believe the answers is because in C++ the enumeration constant 
have the same type of the enum.

In C++, we also can specify the type

Let's say I do this:

enum E : int {
    A = -1,
    B = 0xFFFFFFFFFFFF
};

I got this error:
enumerator value '281474976710655' is outside the range of 
underlying type 'int'

I was going to suggest the same syntax for C, but I am not sure
if it good.
Enums are a very high level feature and abstract.

I think the  decision of making it "real" could be postponed 
to the declaration.

struct X {
  enum E : int e;
}
In this case, the variable e is an int. (If it not big enough
the compiler should emit an warning or error)

The _Bool type is similar. What is the size of the type _Bool?
Maybe this decision should be postponed.
struct X
{
   _Bool : char b1;
   _Bool : char b2;
   _Bool : char b3;
   _Bool : char b4;
};
By default is int. But I may choose char.

[toc] | [prev] | [next] | [standalone]


#150262

FromDavid Brown <david.brown@hesbynett.no>
Date2020-02-26 11:29 +0100
Message-ID<r35hab$ts9$1@dont-email.me>
In reply to#150254
On 26/02/2020 00:38, Thiago Adams wrote:
> From the standard:
> 
> "The identifiers in an enumerator list are declared as constants 
> that have type int and may appear wherever such are permitted.127)"
> 
> But there is a foot note:
> 
> "Each enumerated type shall be compatible with char, a signed 
> integer type, or an unsigned integer type. The choice of type 
> is implementation-defined,128)"
> 
> "128) An implementation may delay the choice of which integer 
> type until all enumeration constants have been seen."
> 
> I am confused. 
> 

You are not the first person to feel that way.

> enum E { A, B};

The key weirdness of "enum" in C is that "enum E" is a type, but A and B
are not objects of that type.  They are, however, members of the
enumeration "E".

"A" and "B" are named integer constant values (much like 'a' and 'b').
So they have type "int".

"enum E" is an enumerated type.  It is an odd thing - it is an integer
type (6.2.5p17), and it is required to be compatible with a char, a
signed integer type, or an unsigned integer type (6.7.2.2p4).  I am sure
it was not intended that this requirement be recursive here!

It is up to the compiler to decide which integer type "enum E" should be
compatible with.  Once it is picked (gcc picks "unsigned int" here,
unless at least one of the enumerators is negative, when it picks
"int"), the type "enum E" is indistinguishable from that type.  So
_Generic() on gcc would match "enum E" as "unsigned int".  As far as I
understand it (and I could be wrong), "enum E" is therefore a new type
that is in every way identical and compatible to an existing type - but
is not an alias for it (like a typedef).

(Of course, compilers and other tools can track a distinction here, and
use it for extra warnings or analysis.)

> 
> Can A and B be int and E not int?

A and B are always "int".  E might not be.

(Many compilers have extensions to allow A and B to be "long int".)

> Can A B and E be != int? 
> 
> If so, what is this 
> 
> "The identifiers in an enumerator list are declared as constants 
> that have type int and may appear wherever such are permitted.127)"
> 

[toc] | [prev] | [next] | [standalone]


#150274

Fromalready5chosen@yahoo.com
Date2020-02-26 14:05 -0800
Message-ID<5c585469-72c8-42f8-9e74-848f160db602@googlegroups.com>
In reply to#150262
On Wednesday, February 26, 2020 at 12:29:40 PM UTC+2, David Brown wrote:
> On 26/02/2020 00:38, Thiago Adams wrote:
> > From the standard:
> > 
> > "The identifiers in an enumerator list are declared as constants 
> > that have type int and may appear wherever such are permitted.127)"
> > 
> > But there is a foot note:
> > 
> > "Each enumerated type shall be compatible with char, a signed 
> > integer type, or an unsigned integer type. The choice of type 
> > is implementation-defined,128)"
> > 
> > "128) An implementation may delay the choice of which integer 
> > type until all enumeration constants have been seen."
> > 
> > I am confused. 
> > 
> 
> You are not the first person to feel that way.
> 
> > enum E { A, B};
> 
> The key weirdness of "enum" in C is that "enum E" is a type, but A and B
> are not objects of that type.  They are, however, members of the
> enumeration "E".
> 
> "A" and "B" are named integer constant values (much like 'a' and 'b').
> So they have type "int".
>

That' how language of the standard sounds.
But it's not how gcc and clang work.

enum enum_t {
 uns = (unsigned)-1,
 neg = -1,
};
Both in gcc and in clang uns has type 'unsigned int' rather than 'int'.
And indeed it differs from type of 'enum_t' which in ths case is 'int'.

Microsoft's compiler (VS2015) is easier to understand and don't violate (my understanding of) Standard, but it is less flexible - everything, including uns, is 'int'.


> "enum E" is an enumerated type.  It is an odd thing - it is an integer
> type (6.2.5p17), and it is required to be compatible with a char, a
> signed integer type, or an unsigned integer type (6.7.2.2p4).  I am sure
> it was not intended that this requirement be recursive here!
> 
> It is up to the compiler to decide which integer type "enum E" should be
> compatible with.  Once it is picked (gcc picks "unsigned int" here,
> unless at least one of the enumerators is negative, when it picks
> "int"), the type "enum E" is indistinguishable from that type.  So
> _Generic() on gcc would match "enum E" as "unsigned int".  As far as I
> understand it (and I could be wrong), "enum E" is therefore a new type
> that is in every way identical and compatible to an existing type - but
> is not an alias for it (like a typedef).
> 
> (Of course, compilers and other tools can track a distinction here, and
> use it for extra warnings or analysis.)
> 
> > 
> > Can A and B be int and E not int?
> 
> A and B are always "int".  E might not be.
> 
> (Many compilers have extensions to allow A and B to be "long int".)
> 
> > Can A B and E be != int? 
> > 
> > If so, what is this 
> > 
> > "The identifiers in an enumerator list are declared as constants 
> > that have type int and may appear wherever such are permitted.127)"
> >

[toc] | [prev] | [next] | [standalone]


#150275

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2020-02-26 23:03 +0000
Message-ID<875zftx86i.fsf@bsb.me.uk>
In reply to#150274
already5chosen@yahoo.com writes:

> On Wednesday, February 26, 2020 at 12:29:40 PM UTC+2, David Brown wrote:
<cut>
>> "A" and "B" are named integer constant values (much like 'a' and 'b').
>> So they have type "int".
>
> That' how language of the standard sounds.
> But it's not how gcc and clang work.
>
> enum enum_t {
>  uns = (unsigned)-1,

This violates a constraint.  Recent gcc and clang do indeed report it.

>  neg = -1,
> };
> Both in gcc and in clang uns has type 'unsigned int' rather than
> 'int'.

The program has undefined behaviour by this point.  gcc and clang and
making a good job of trying to work out what the program should
reasonably do.

> And indeed it differs from type of 'enum_t' which in ths case is 'int'.
>
> Microsoft's compiler (VS2015) is easier to understand and don't
> violate (my understanding of) Standard, but it is less flexible -
> everything, including uns, is 'int'.

What int value does VS2015 pick for uns?  I can see to plausible
choices, INT_MAX and -1.

<cut>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#150277

Fromalready5chosen@yahoo.com
Date2020-02-26 23:29 -0800
Message-ID<ba74eacb-4054-4543-bfb0-0eb346b20208@googlegroups.com>
In reply to#150275
On Thursday, February 27, 2020 at 1:03:57 AM UTC+2, Ben Bacarisse wrote:
> already5chosen@yahoo.com writes:
> 
> > On Wednesday, February 26, 2020 at 12:29:40 PM UTC+2, David Brown wrote:
> <cut>
> >> "A" and "B" are named integer constant values (much like 'a' and 'b').
> >> So they have type "int".
> >
> > That' how language of the standard sounds.
> > But it's not how gcc and clang work.
> >
> > enum enum_t {
> >  uns = (unsigned)-1,
> 
> This violates a constraint.  Recent gcc and clang do indeed report it.
> 
> >  neg = -1,
> > };
> > Both in gcc and in clang uns has type 'unsigned int' rather than
> > 'int'.
> 
> The program has undefined behaviour by this point.  gcc and clang and
> making a good job of trying to work out what the program should
> reasonably do.
> 
> > And indeed it differs from type of 'enum_t' which in ths case is 'int'.
> >
> > Microsoft's compiler (VS2015) is easier to understand and don't
> > violate (my understanding of) Standard, but it is less flexible -
> > everything, including uns, is 'int'.
> 
> What int value does VS2015 pick for uns?  I can see to plausible
> choices, INT_MAX and -1.
> 
> <cut>
> -- 
> Ben.

Of course -1. Microsoft compiler guys are strongly in "wrapping" camp. Or, at least, they were strongly in "wrapping" camp before they started to flirt with LLVM.

[toc] | [prev] | [next] | [standalone]


#150283

Fromalready5chosen@yahoo.com
Date2020-02-27 01:42 -0800
Message-ID<3490308b-ac71-4f70-a62a-0f8e0db41b02@googlegroups.com>
In reply to#150277
On Thursday, February 27, 2020 at 9:29:43 AM UTC+2, already...@yahoo.com wrote:
> On Thursday, February 27, 2020 at 1:03:57 AM UTC+2, Ben Bacarisse wrote:
> > already5chosen@yahoo.com writes:
> > 
> > > On Wednesday, February 26, 2020 at 12:29:40 PM UTC+2, David Brown wrote:
> > <cut>
> > >> "A" and "B" are named integer constant values (much like 'a' and 'b').
> > >> So they have type "int".
> > >
> > > That' how language of the standard sounds.
> > > But it's not how gcc and clang work.
> > >
> > > enum enum_t {
> > >  uns = (unsigned)-1,
> > 
> > This violates a constraint.  Recent gcc and clang do indeed report it.
> > 
> > >  neg = -1,
> > > };
> > > Both in gcc and in clang uns has type 'unsigned int' rather than
> > > 'int'.
> > 
> > The program has undefined behaviour by this point.  gcc and clang and
> > making a good job of trying to work out what the program should
> > reasonably do.
> > 
> > > And indeed it differs from type of 'enum_t' which in ths case is 'int'.
> > >
> > > Microsoft's compiler (VS2015) is easier to understand and don't
> > > violate (my understanding of) Standard, but it is less flexible -
> > > everything, including uns, is 'int'.
> > 
> > What int value does VS2015 pick for uns?  I can see to plausible
> > choices, INT_MAX and -1.
> > 
> > <cut>
> > -- 
> > Ben.
> 
> Of course -1. Microsoft compiler guys are strongly in "wrapping" camp. Or, at least, they were strongly in "wrapping" camp before they started to flirt with LLVM.

Thinking about it, it's not just about wrapping vs nasal demons.
If assignment of unsigned value in range [INT_MAX..UINT_MAX] to integer is not treated as bit-by-bit copy then it will break a huge amount of working code. So, even LLVM/clang maintainers, which are, despite their religion, practical people, and are paid by VERY practical corporations, will not never do it.

[toc] | [prev] | [next] | [standalone]


#150286

FromDavid Brown <david.brown@hesbynett.no>
Date2020-02-27 11:02 +0100
Message-ID<r3843n$eeq$1@dont-email.me>
In reply to#150283
On 27/02/2020 10:42, already5chosen@yahoo.com wrote:
> On Thursday, February 27, 2020 at 9:29:43 AM UTC+2,
> already...@yahoo.com wrote:
>> On Thursday, February 27, 2020 at 1:03:57 AM UTC+2, Ben Bacarisse


>>> 
>>> What int value does VS2015 pick for uns?  I can see to plausible 
>>> choices, INT_MAX and -1.
>>> 
>>> <cut> -- Ben.
>> 
>> Of course -1. Microsoft compiler guys are strongly in "wrapping"
>> camp. Or, at least, they were strongly in "wrapping" camp before
>> they started to flirt with LLVM.
> 
> Thinking about it, it's not just about wrapping vs nasal demons. If
> assignment of unsigned value in range [INT_MAX..UINT_MAX] to integer
> is not treated as bit-by-bit copy then it will break a huge amount of
> working code. So, even LLVM/clang maintainers, which are, despite
> their religion, practical people, and are paid by VERY practical
> corporations, will not never do it.
> 

You are conflating three related but different issues here, as far as I
can see.

1. Arithmetic overflow of signed integers is /undefined behaviour/ in C.
 A few compilers guarantee wrapping behaviour - most (in my experience)
do not.  That includes MSVC - it does /not/ guarantee wrapping of signed
arithmetic.  It rarely optimises on the assumption that overflow does
not occur, but it sometimes does so.  (I have tested this, but can't
remember the example I found that showed such optimisation.)  gcc and
clang are more inclined to optimise on the assumption that signed
integer overflow does not work.  Both these compilers have an option
(-fwrapv) that changes the semantics of the language to say that signed
integer arithmetic should wrap, for those that rely on this behaviour.

Thus gcc/clang give you the best of both worlds - as the programmer, you
can choose if you want guaranteed wrapping, or more efficient code.

MSVC gives you the worst option - it looks like you get wrapping, it
generates less efficient code than it could do, but you are not
guaranteed this behaviour and can't rely on it.  (It is possible that
MSVC has a compiler switch equivalent to "-fwrapv" that I have not noticed.)


2. Conversions between unsigned integers and signed integers are
/implementation-dependent/ when the value is outside the range of the
destination type.  That means the compiler must have a specific,
documented way of handling it.  All (AFAIK) compilers with normal
unpadded two's complement signed integer types will handle this by
wrapping, which is equivalent to bit-by-bit copy.  Compilers (and
compiler writers) do not have the option of handling this in different
ways, or assuming it does not happen.


3. The original code had an enumerator "uns = (unsigned) -1".  The
conversion of -1 to unsigned is implementation defined (see point 2
above).  The resulting value is not within the range of "int", and
breaks a constraint (in 6.7.2.2p2).  A conforming compiler is required
to issue a diagnostic - something that gcc does if put in stricter modes
(like "-Wpedantic").  A less strict compiler can treat it in any way it
feels reasonable.  gcc does this by making "uns" an unsigned integer
constant (and making the enumerated type unsigned).  MSVC does this by
converting it to an int, arriving back at -1.  Both are perfectly
acceptable in non-strict modes.  Ben's suggestion of saturating at
INT_MAX is also acceptable, if unlikely.

Personally, I hugely prefer gcc's choice here.  If I have written
"unsigned" explicitly, I want an unsigned.  If the compiler can't give
me that, a diagnostic message (as required by the standards) is a
reasonable alternative.  Choosing a completely different value
(regardless of similarities in bit patterns) is not helpful.

[toc] | [prev] | [next] | [standalone]


#150298

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2020-02-27 06:37 -0800
Message-ID<87eeugt7ub.fsf@nosuchdomain.example.com>
In reply to#150286
David Brown <david.brown@hesbynett.no> writes:
[...]
> 3. The original code had an enumerator "uns = (unsigned) -1".  The
> conversion of -1 to unsigned is implementation defined (see point 2
> above).
[...]

The result of converting -1 to unsigned is UINT_MAX.  It's not
implementation-defined.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#150301

FromDavid Brown <david.brown@hesbynett.no>
Date2020-02-27 16:18 +0100
Message-ID<r38mkr$lqk$1@dont-email.me>
In reply to#150298
On 27/02/2020 15:37, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
> [...]
>> 3. The original code had an enumerator "uns = (unsigned) -1".  The
>> conversion of -1 to unsigned is implementation defined (see point 2
>> above).
> [...]
> 
> The result of converting -1 to unsigned is UINT_MAX.  It's not
> implementation-defined.
> 

Yes - it is conversion from unsigned to signed types that is
implementation defined (if the value is outside the range).  So it is
the conversion from "(unsigned) -1" back to an int that is
implementation defined.  Sorry for the inaccuracy here.

[toc] | [prev] | [next] | [standalone]


#150323

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2020-02-27 23:24 -0500
Message-ID<r3a4mb$c10$1@dont-email.me>
In reply to#150301
On 2/27/20 10:18 AM, David Brown wrote:
> On 27/02/2020 15:37, Keith Thompson wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>> [...]
>>> 3. The original code had an enumerator "uns = (unsigned) -1".  The
>>> conversion of -1 to unsigned is implementation defined (see point 2
>>> above).
>> [...]
>>
>> The result of converting -1 to unsigned is UINT_MAX.  It's not
>> implementation-defined.
>>
> 
> Yes - it is conversion from unsigned to signed types that is
> implementation defined (if the value is outside the range).  So it is
> the conversion from "(unsigned) -1" back to an int that is
> implementation defined.  Sorry for the inaccuracy here.

The standard doesn't specify that the constant-expression gets converted
to int. It specifies that the constant expression provides the value for
the enumerator, and imposes a constraint that this value be
representable as an int. The problem is that it violates that constraint.

[toc] | [prev] | [next] | [standalone]


#150279

FromDavid Brown <david.brown@hesbynett.no>
Date2020-02-27 09:50 +0100
Message-ID<r37vss$f30$1@dont-email.me>
In reply to#150274
On 26/02/2020 23:05, already5chosen@yahoo.com wrote:
> On Wednesday, February 26, 2020 at 12:29:40 PM UTC+2, David Brown wrote:
>> On 26/02/2020 00:38, Thiago Adams wrote:
>>> From the standard:
>>>
>>> "The identifiers in an enumerator list are declared as constants 
>>> that have type int and may appear wherever such are permitted.127)"
>>>
>>> But there is a foot note:
>>>
>>> "Each enumerated type shall be compatible with char, a signed 
>>> integer type, or an unsigned integer type. The choice of type 
>>> is implementation-defined,128)"
>>>
>>> "128) An implementation may delay the choice of which integer 
>>> type until all enumeration constants have been seen."
>>>
>>> I am confused. 
>>>
>>
>> You are not the first person to feel that way.
>>
>>> enum E { A, B};
>>
>> The key weirdness of "enum" in C is that "enum E" is a type, but A and B
>> are not objects of that type.  They are, however, members of the
>> enumeration "E".
>>
>> "A" and "B" are named integer constant values (much like 'a' and 'b').
>> So they have type "int".
>>
> 
> That' how language of the standard sounds.
> But it's not how gcc and clang work.
> 
> enum enum_t {
>  uns = (unsigned)-1,
>  neg = -1,
> };
> Both in gcc and in clang uns has type 'unsigned int' rather than 'int'.
> And indeed it differs from type of 'enum_t' which in ths case is 'int'.

This is an extension that these tools support - as do many compilers.
If you want to ensure that you stick to standards-only code, use
"-Wpedantic" (along with your choice of -std=c11, -std=c99 or -std=c90),
and pay attention to the warnings.  The C standard does not say how
"uns" should be treated, gcc's extensions do the "obvious" thing.

> 
> Microsoft's compiler (VS2015) is easier to understand and don't
> violate (my understanding of) Standard, but it is less flexible -
> everything, including uns, is 'int'.
> 

Extensions don't violate the standard if they give defined effects to
something the standards don't define - they only violate it if they stop
otherwise valid C code being properly handled (such as gcc's "asm"
extension conflicting with an identifier "asm" in standard C), or if the
compiler fails to give a mandatory diagnostic.

[toc] | [prev] | [next] | [standalone]


#150297

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2020-02-27 06:33 -0800
Message-ID<87imjst80s.fsf@nosuchdomain.example.com>
In reply to#150279
David Brown <david.brown@hesbynett.no> writes:
[...]
>> enum enum_t {
>>  uns = (unsigned)-1,
>>  neg = -1,
>> };
>> Both in gcc and in clang uns has type 'unsigned int' rather than 'int'.
>> And indeed it differs from type of 'enum_t' which in ths case is 'int'.
>
> This is an extension that these tools support - as do many compilers.
> If you want to ensure that you stick to standards-only code, use
> "-Wpedantic" (along with your choice of -std=c11, -std=c99 or -std=c90),
> and pay attention to the warnings.  The C standard does not say how
> "uns" should be treated, gcc's extensions do the "obvious" thing.

Ah, but gcc doesn't print a diagnostic with "-std=c11 -Wpedantic", even
though the code violates a constraint.

N1570 6.7.2.2p2:

    The expression that defines the value of an enumeration constant
    shall be an integer constant expression that has a value
    representable as an int.

Even my copy of gcc built from source that calls itself
    gcc (GCC) 10.0.0 20200111 (experimental)
fails to diagnose it.

A recent version of clang does print a diagnostic.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#150299

Fromalready5chosen@yahoo.com
Date2020-02-27 06:53 -0800
Message-ID<686794bc-f64f-4b0e-850c-b899d74d06b0@googlegroups.com>
In reply to#150297
On Thursday, February 27, 2020 at 4:33:17 PM UTC+2, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
> [...]
> >> enum enum_t {
> >>  uns = (unsigned)-1,
> >>  neg = -1,
> >> };
> >> Both in gcc and in clang uns has type 'unsigned int' rather than 'int'.
> >> And indeed it differs from type of 'enum_t' which in ths case is 'int'.
> >
> > This is an extension that these tools support - as do many compilers.
> > If you want to ensure that you stick to standards-only code, use
> > "-Wpedantic" (along with your choice of -std=c11, -std=c99 or -std=c90),
> > and pay attention to the warnings.  The C standard does not say how
> > "uns" should be treated, gcc's extensions do the "obvious" thing.
> 
> Ah, but gcc doesn't print a diagnostic with "-std=c11 -Wpedantic", even
> though the code violates a constraint.
> 

Try -Wall -pedantic

> N1570 6.7.2.2p2:
> 
>     The expression that defines the value of an enumeration constant
>     shall be an integer constant expression that has a value
>     representable as an int.
> 
> Even my copy of gcc built from source that calls itself
>     gcc (GCC) 10.0.0 20200111 (experimental)
> fails to diagnose it.
> 
> A recent version of clang does print a diagnostic.
> 
> -- 
> Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
> Working, but not speaking, for Philips Healthcare
> void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#150300

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2020-02-27 15:05 +0000
Message-ID<877e08vzng.fsf@bsb.me.uk>
In reply to#150297
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

> David Brown <david.brown@hesbynett.no> writes:
> [...]
>>> enum enum_t {
>>>  uns = (unsigned)-1,
>>>  neg = -1,
>>> };
>>> Both in gcc and in clang uns has type 'unsigned int' rather than 'int'.
>>> And indeed it differs from type of 'enum_t' which in ths case is 'int'.
>>
>> This is an extension that these tools support - as do many compilers.
>> If you want to ensure that you stick to standards-only code, use
>> "-Wpedantic" (along with your choice of -std=c11, -std=c99 or -std=c90),
>> and pay attention to the warnings.  The C standard does not say how
>> "uns" should be treated, gcc's extensions do the "obvious" thing.
>
> Ah, but gcc doesn't print a diagnostic with "-std=c11 -Wpedantic", even
> though the code violates a constraint.

Oh.  It does for me:

$ cat enum.c
enum enum_t {
     uns = (unsigned)-1,
     neg = -1,
};
$ gcc -std=c11 -Wpedantic -c enum.c
enum.c:2:12: warning: ISO C restricts enumerator values to range of ‘int’ [-Wpedantic]
      uns = (unsigned)-1,
            ^
$ gcc --version                                                               ✘
gcc (Ubuntu 8.3.0-6ubuntu1) 8.3.0

<cut>
> Even my copy of gcc built from source that calls itself
>     gcc (GCC) 10.0.0 20200111 (experimental)
> fails to diagnose it.
>
> A recent version of clang does print a diagnostic.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#150302

FromDavid Brown <david.brown@hesbynett.no>
Date2020-02-27 16:24 +0100
Message-ID<r38muq$pfg$1@dont-email.me>
In reply to#150297
On 27/02/2020 15:33, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
> [...]
>>> enum enum_t {
>>>  uns = (unsigned)-1,
>>>  neg = -1,
>>> };
>>> Both in gcc and in clang uns has type 'unsigned int' rather than 'int'.
>>> And indeed it differs from type of 'enum_t' which in ths case is 'int'.
>>
>> This is an extension that these tools support - as do many compilers.
>> If you want to ensure that you stick to standards-only code, use
>> "-Wpedantic" (along with your choice of -std=c11, -std=c99 or -std=c90),
>> and pay attention to the warnings.  The C standard does not say how
>> "uns" should be treated, gcc's extensions do the "obvious" thing.
> 
> Ah, but gcc doesn't print a diagnostic with "-std=c11 -Wpedantic", even
> though the code violates a constraint.
> 
> N1570 6.7.2.2p2:
> 
>     The expression that defines the value of an enumeration constant
>     shall be an integer constant expression that has a value
>     representable as an int.
> 
> Even my copy of gcc built from source that calls itself
>     gcc (GCC) 10.0.0 20200111 (experimental)
> fails to diagnose it.
> 
> A recent version of clang does print a diagnostic.
> 

A random selection of gcc versions from godbolt.org all give a warning
on "uns" here.  Maybe there is something odd going on here (including a
possible bug in the pre-release gcc you have, though 10.0.1 on
godbolt.org gives the warning fine).

[toc] | [prev] | [next] | [standalone]


#150326

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2020-02-28 01:27 -0800
Message-ID<87a753t624.fsf@nosuchdomain.example.com>
In reply to#150297
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
> David Brown <david.brown@hesbynett.no> writes:
> [...]
>>> enum enum_t {
>>>  uns = (unsigned)-1,
>>>  neg = -1,
>>> };
>>> Both in gcc and in clang uns has type 'unsigned int' rather than 'int'.
>>> And indeed it differs from type of 'enum_t' which in ths case is 'int'.
>>
>> This is an extension that these tools support - as do many compilers.
>> If you want to ensure that you stick to standards-only code, use
>> "-Wpedantic" (along with your choice of -std=c11, -std=c99 or -std=c90),
>> and pay attention to the warnings.  The C standard does not say how
>> "uns" should be treated, gcc's extensions do the "obvious" thing.
>
> Ah, but gcc doesn't print a diagnostic with "-std=c11 -Wpedantic", even
> though the code violates a constraint.

Um, yes it does.  I don't know what I did wrong that led me to think
otherwise.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#150280

Fromalready5chosen@yahoo.com
Date2020-02-27 01:29 -0800
Message-ID<aafdcd8f-ba2e-4237-9df9-c9808a34b78f@googlegroups.com>
In reply to#150274
On Thursday, February 27, 2020 at 12:05:12 AM UTC+2, already...@yahoo.com wrote:
> On Wednesday, February 26, 2020 at 12:29:40 PM UTC+2, David Brown wrote:
> > On 26/02/2020 00:38, Thiago Adams wrote:
> > > From the standard:
> > > 
> > > "The identifiers in an enumerator list are declared as constants 
> > > that have type int and may appear wherever such are permitted.127)"
> > > 
> > > But there is a foot note:
> > > 
> > > "Each enumerated type shall be compatible with char, a signed 
> > > integer type, or an unsigned integer type. The choice of type 
> > > is implementation-defined,128)"
> > > 
> > > "128) An implementation may delay the choice of which integer 
> > > type until all enumeration constants have been seen."
> > > 
> > > I am confused. 
> > > 
> > 
> > You are not the first person to feel that way.
> > 
> > > enum E { A, B};
> > 
> > The key weirdness of "enum" in C is that "enum E" is a type, but A and B
> > are not objects of that type.  They are, however, members of the
> > enumeration "E".
> > 
> > "A" and "B" are named integer constant values (much like 'a' and 'b').
> > So they have type "int".
> >
> 
> That' how language of the standard sounds.
> But it's not how gcc and clang work.
> 
> enum enum_t {
>  uns = (unsigned)-1,
>  neg = -1,
> };
> Both in gcc and in clang uns has type 'unsigned int' rather than 'int'.
> And indeed it differs from type of 'enum_t' which in ths case is 'int'.
> 
> Microsoft's compiler (VS2015) is easier to understand and don't violate (my understanding of) Standard, but it is less flexible - everything, including uns, is 'int'.
> 
> 
> > "enum E" is an enumerated type.  It is an odd thing - it is an integer
> > type (6.2.5p17), and it is required to be compatible with a char, a
> > signed integer type, or an unsigned integer type (6.7.2.2p4).  I am sure
> > it was not intended that this requirement be recursive here!
> > 
> > It is up to the compiler to decide which integer type "enum E" should be
> > compatible with.  Once it is picked (gcc picks "unsigned int" here,
> > unless at least one of the enumerators is negative, when it picks
> > "int"), the type "enum E" is indistinguishable from that type.  So
> > _Generic() on gcc would match "enum E" as "unsigned int".  As far as I
> > understand it (and I could be wrong), "enum E" is therefore a new type
> > that is in every way identical and compatible to an existing type - but
> > is not an alias for it (like a typedef).
> > 
> > (Of course, compilers and other tools can track a distinction here, and
> > use it for extra warnings or analysis.)
> > 
> > > 
> > > Can A and B be int and E not int?
> > 
> > A and B are always "int".  E might not be.
> > 
> > (Many compilers have extensions to allow A and B to be "long int".)
> > 

In case of Windows port of gcc and clang, even 'long long int',
This case is especially funny:

enum en_t {
  A = 1,
  B = -1,
  C = (unsigned)-1,
};

type of en_t is 'long long'
A == 1, type is either 'int' or 'unsigned', I can't tell for sure
B == -1, type is 'int
C == 2**32-1, type is 'long long' or 'unsigned long long', I can't tell for sure.

Again, that's on Windows/Msys2. 
On Linux, I wouldn't know how to distinguish between rvalues of types 'long' and 'long long'.

> > > Can A B and E be != int? 
> > > 
> > > If so, what is this 
> > > 
> > > "The identifiers in an enumerator list are declared as constants 
> > > that have type int and may appear wherever such are permitted.127)"
> > >

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web