enum as bitfields

Discussion in 'C Programming' started by Quentin Pope, Sep 29, 2011.

  1. Quentin Pope

    Quentin Pope Guest

    Hello,

    Does the C standard say anything about using enum in a bit field? Like

    enum {
    apple,
    orange

    } fruit;

    struct {
    enum fruit f:16;

    };

    Gcc does not complain about this when -ansi or -pedantic is turned
    OFF. XLC (claims to be an ANSI C compiler) on the IBM RS/6000 issued
    a warning and treat it like an unsigned integer. K&R 2nd Ed says
    nothing explicitly about this but it says that bit fields are
    `implementation dependant' and `always unsigned'.

    I think this is very useful and in our project we encourage people to use
    enum instead of #define to create constants. Although not used in a lot
    of places, the bit field somewhat defeats this purpose. Is there a
    rationale why this is so? Is there any way to shut up the compiler?
    I've checked the FAQ. No answers from there.

    Thanks
    QP
    Quentin Pope, Sep 29, 2011
    #1
    1. Advertising

  2. Quentin Pope

    James Kuyper Guest

    On 09/29/2011 04:30 PM, Quentin Pope wrote:
    > Hello,
    >
    > Does the C standard say anything about using enum in a bit field? Like
    >
    > enum {
    > apple,
    > orange
    >
    > } fruit;
    >
    > struct {
    > enum fruit f:16;
    >
    > };
    >
    > Gcc does not complain about this when -ansi or -pedantic is turned
    > OFF. XLC (claims to be an ANSI C compiler) on the IBM RS/6000 issued
    > a warning and treat it like an unsigned integer.


    6.7.2.1p4: "A bit-field shall have a type that is a qualified or
    unqualified version of _Bool, signed int, unsigned int, or some other
    implementation-defined type."

    This means that an implementation can accept other types, in which case
    no diagnostic is required, but that an implementation is not required to
    accept any other types. Code that's intended to be portable should
    therefore not use other types.

    > ... K&R 2nd Ed says
    > nothing explicitly about this but it says that bit fields are
    > `implementation dependant' and `always unsigned'.


    Many features of bit fields are implementation-dependent; but it's not
    clear which of those features that comment might be about. A bit field
    declared as 'signed int' is unambiguously signed. Are you sure that K&R2
    claims that bit-fields are "always unsigned"?

    6.7.2.1p4 seems to imply that an implementation is not required to
    accept a bit field declared with plain 'int', something I had not
    noticed before. However, if an implementation does accept it, then
    6.7.2p5 applies: "for bit-fields, it is implementation-defined whether
    the specifier int designates the same type as signed int or the same
    type as unsigned int." From this I conclude that, even if an
    implementation does allow use of plain 'int' for bit fields, no sane
    programmer should ever take advantage of that fact.
    James Kuyper, Sep 29, 2011
    #2
    1. Advertising

  3. Quentin Pope <> writes:
    > Does the C standard say anything about using enum in a bit field? Like
    >
    > enum {
    > apple,
    > orange
    >
    > } fruit;
    >
    > struct {
    > enum fruit f:16;
    >
    > };


    Yes. C99 6.7.2.1p4:

    A bit-field shall have a type that is a qualified or unqualified
    version of _Bool, signed int, unsigned int, or some other
    implementation-defined type.

    This is a constraint, and "implementation-defined" means that the
    ipmlementation must document any other types, so the compiler (in
    conforming mode) must complain about an enum bit-field *unless*
    the compiler's documentation specifically says that it's permitted.

    More generally, using a bit field of a type other than the ones
    listed in the standard makes your code non-portable. (Using bit
    fields is likely to do that as well, if you're assuming that it
    defines the layout precisely.)

    [...]

    > I think this is very useful and in our project we encourage people to use
    > enum instead of #define to create constants. Although not used in a lot
    > of places, the bit field somewhat defeats this purpose. Is there a
    > rationale why this is so? Is there any way to shut up the compiler?
    > I've checked the FAQ. No answers from there.


    In the example you've shown us, making "f" a bit field doesn't make much
    sense; it would be simpler to write just "enum fruit f;". Why do you
    need f to be exactly 16 bits?

    If your purpose is to define some constants, you can use enumerations
    without necessarily using the enumeration type. For example:

    enum { apple, orange };
    struct basket { unsigned f:16; };
    struct basket b;

    b.f = apple;

    Enumeration constants in C are not actually of the enumeration type;
    they're always of type int.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Sep 29, 2011
    #3
  4. Quentin Pope <> writes:

    > Does the C standard say anything about using enum in a bit field? Like
    >
    > enum {
    > apple,
    > orange
    >
    > } fruit;


    (you mean enum fruit {...}; not enum {...} fruit; I think)

    > struct {
    > enum fruit f:16;
    >
    > };


    Yes, it does. There is a constraint:

    A bit-field shall have a type that is a qualified or unqualified
    version of _Bool, signed int, unsigned int, or some other
    implementation-defined type.

    which, if violated would make your program undefined and would require a
    diagnostic. However, from the wording it would seem that an
    implementation that documents the possibility of using an enum, may
    accept this code without saying a word.

    > Gcc does not complain about this when -ansi or -pedantic is turned
    > OFF. XLC (claims to be an ANSI C compiler) on the IBM RS/6000 issued
    > a warning and treat it like an unsigned integer. K&R 2nd Ed says
    > nothing explicitly about this but it says that bit fields are
    > `implementation dependant' and `always unsigned'.


    You may be misreporting this. K&R2 sticks close to what was called ANSI
    C, and in ANSI C, bit fields can be signed. My quote above is from the
    newer 1999 C standard.

    > I think this is very useful and in our project we encourage people to use
    > enum instead of #define to create constants. Although not used in a lot
    > of places, the bit field somewhat defeats this purpose. Is there a
    > rationale why this is so? Is there any way to shut up the compiler?


    There might be. You name two compilers and the one that complains is
    one I don't know. gcc also has something to say if put into conforming
    mode, though what it does is simply to remind you that this is an
    extension:

    $ gcc -std=c99 -pedantic -c x.c
    x.c:8:8: warning: type of bit-field ‘f’ is a GCC extension

    I don't think this is one you can turn off. My reading of the standard
    is that gcc could silently accept this code in conforming mode, but it
    is not obliged to do so. A compiler is permitted to issue pretty much
    any diagnostics it likes, as far as the standard is concerned.

    --
    Ben.
    Ben Bacarisse, Sep 29, 2011
    #4
  5. Quentin Pope

    Ben Pfaff Guest

    Quentin Pope <> writes:

    > Does the C standard say anything about using enum in a bit field?


    It doesn't say that it's allowed, except as an implementation
    extension:

    4 A bit-field shall have a type that is a qualified or
    unqualified version of _Bool, signed int, unsigned int, or
    some other implementation-defined type.

    --
    Ben Pfaff
    http://benpfaff.org
    Ben Pfaff, Sep 29, 2011
    #5
  6. James Kuyper <> writes:
    [...]
    > 6.7.2.1p4: "A bit-field shall have a type that is a qualified or
    > unqualified version of _Bool, signed int, unsigned int, or some other
    > implementation-defined type."

    [...]

    > 6.7.2.1p4 seems to imply that an implementation is not required to
    > accept a bit field declared with plain 'int', something I had not
    > noticed before.


    I don't think so. The same reasoning would imply that you can't declare
    a bit-field as "unsigned", "int unsigned", or "signed". 6.7.2p2
    indicates that "int", "signed", and "signed int" are all names for the
    same type.

    I'm 99% sure that the intent is implementations are required to support
    that plain "int" bit-fields.

    > However, if an implementation does accept it, then
    > 6.7.2p5 applies: "for bit-fields, it is implementation-defined whether
    > the specifier int designates the same type as signed int or the same
    > type as unsigned int." From this I conclude that, even if an
    > implementation does allow use of plain 'int' for bit fields, no sane
    > programmer should ever take advantage of that fact.


    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Sep 30, 2011
    #6
  7. On Sep 30, 6:11 am, Keith Thompson <> wrote:
    > James Kuyper <> writes:
    >
    > [...]> 6.7.2.1p4: "A bit-field shall have a type that is a qualified or
    > > unqualified version of _Bool, signed int, unsigned int, or some other
    > > implementation-defined type."

    >
    > [...]
    >
    > > 6.7.2.1p4 seems to imply that an implementation is not required to
    > > accept a bit field declared with plain 'int', something I had not
    > > noticed before.

    >
    > I don't think so.  The same reasoning would imply that you can't declare
    > a bit-field as "unsigned", "int unsigned", or "signed".  6.7.2p2
    > indicates that "int", "signed", and "signed int" are all names for the
    > same type.


    Bit-fields are a special case where int and signed int are not
    necessarily synonymous: plain int may be treated as either signed or
    unsigned. However, whichever it is, it is not like char, where plain
    char is a distinct type from the signed and unsigned varieties.
    6.7.2p5 makes it clear that plain int is either signed int, or
    unsigned int.

    > I'm 99% sure that the intent is implementations are required to support
    > that plain "int" bit-fields.


    Sure.
    Harald van Dijk, Sep 30, 2011
    #7
  8. Quentin Pope

    Quentin Pope Guest

    On Thu, 29 Sep 2011 22:11:18 +0100, Ben Bacarisse wrote:

    > Quentin Pope <> writes:
    >
    >> Does the C standard say anything about using enum in a bit field? Like
    >>
    >> enum {
    >> apple,
    >> orange
    >>
    >> } fruit;

    >
    > (you mean enum fruit {...}; not enum {...} fruit; I think)
    >
    >> struct {
    >> enum fruit f:16;
    >>
    >> };

    >
    > Yes, it does. There is a constraint:
    >
    > A bit-field shall have a type that is a qualified or unqualified
    > version of _Bool, signed int, unsigned int, or some other
    > implementation-defined type.
    >
    > which, if violated would make your program undefined and would require a
    > diagnostic. However, from the wording it would seem that an
    > implementation that documents the possibility of using an enum, may
    > accept this code without saying a word.


    So in effect, it may or may not be a constraint violation, depending on
    whether the underlying type of the enum is int, unsigned int or something
    else?
    Quentin Pope, Oct 1, 2011
    #8
  9. Quentin Pope

    James Kuyper Guest

    On 10/01/2011 04:59 AM, Quentin Pope wrote:
    > On Thu, 29 Sep 2011 22:11:18 +0100, Ben Bacarisse wrote:
    >
    >> Quentin Pope <> writes:
    >>
    >>> Does the C standard say anything about using enum in a bit field? Like
    >>>
    >>> enum {
    >>> apple,
    >>> orange
    >>>
    >>> } fruit;

    >>
    >> (you mean enum fruit {...}; not enum {...} fruit; I think)
    >>
    >>> struct {
    >>> enum fruit f:16;
    >>>
    >>> };

    >>
    >> Yes, it does. There is a constraint:
    >>
    >> A bit-field shall have a type that is a qualified or unqualified
    >> version of _Bool, signed int, unsigned int, or some other
    >> implementation-defined type.
    >>
    >> which, if violated would make your program undefined and would require a
    >> diagnostic. However, from the wording it would seem that an
    >> implementation that documents the possibility of using an enum, may
    >> accept this code without saying a word.

    >
    > So in effect, it may or may not be a constraint violation, depending on
    > whether the underlying type of the enum is int, unsigned int or something
    > else?


    No - the underlying type of the enum is irrelevant. What is relevant is
    the implementation's documentation: any additional types that the
    documentation says are acceptable may be used. Since "A bit-field is
    interpreted as a signed or unsigned integer type" (6.7.2.1p9), it
    wouldn't make much sense for an implementation to accept non-integral
    types. However, as far as the constraint listed above is concerned, if
    an implementation were to document that it accepts 'double' as a type
    for a bit-field, then even "double f:16" would not be a violation of the
    constraint listed above.

    Of course, portable code should only use the types that are guaranteed
    to be allowed.
    --
    James Kuyper
    James Kuyper, Oct 1, 2011
    #9
  10. Quentin Pope

    Quentin Pope Guest

    On Sat, 01 Oct 2011 06:37:23 -0400, James Kuyper wrote:

    > On 10/01/2011 04:59 AM, Quentin Pope wrote:
    >> On Thu, 29 Sep 2011 22:11:18 +0100, Ben Bacarisse wrote:
    >>
    >>> Quentin Pope <> writes:
    >>>
    >>>> Does the C standard say anything about using enum in a bit field?
    >>>> Like
    >>>>
    >>>> enum {
    >>>> apple,
    >>>> orange
    >>>>
    >>>> } fruit;
    >>>
    >>> (you mean enum fruit {...}; not enum {...} fruit; I think)
    >>>
    >>>> struct {
    >>>> enum fruit f:16;
    >>>>
    >>>> };
    >>>
    >>> Yes, it does. There is a constraint:
    >>>
    >>> A bit-field shall have a type that is a qualified or unqualified
    >>> version of _Bool, signed int, unsigned int, or some other
    >>> implementation-defined type.
    >>>
    >>> which, if violated would make your program undefined and would require
    >>> a diagnostic. However, from the wording it would seem that an
    >>> implementation that documents the possibility of using an enum, may
    >>> accept this code without saying a word.

    >>
    >> So in effect, it may or may not be a constraint violation, depending on
    >> whether the underlying type of the enum is int, unsigned int or
    >> something else?

    >
    > No - the underlying type of the enum is irrelevant. What is relevant is
    > the implementation's documentation: any additional types that the
    > documentation says are acceptable may be used. Since "A bit-field is
    > interpreted as a signed or unsigned integer type" (6.7.2.1p9), it
    > wouldn't make much sense for an implementation to accept non-integral
    > types. However, as far as the constraint listed above is concerned, if
    > an implementation were to document that it accepts 'double' as a type
    > for a bit-field, then even "double f:16" would not be a violation of the
    > constraint listed above.
    >
    > Of course, portable code should only use the types that are guaranteed
    > to be allowed.


    James

    I think you may have misunderstood what I was saying.

    My point was that if the enum type is an alias for int, then that is one
    of the allowed types for a bitfield with no need for any implementation
    documentation.

    So although the code won't be portable to every implementation, it will
    still be portable (no constraint violation) for all implementations where
    enums have type int.
    Quentin Pope, Oct 1, 2011
    #10
  11. On Oct 1, 11:21 pm, Quentin Pope <> wrote:
    > On Sat, 01 Oct 2011 06:37:23 -0400, James Kuyper wrote:
    > > On 10/01/2011 04:59 AM, Quentin Pope wrote:
    > >> On Thu, 29 Sep 2011 22:11:18 +0100, Ben Bacarisse wrote:
    > >>> Quentin Pope <> writes:
    > >>>   A bit-field shall have a type that is a qualified or unqualified
    > >>>   version of _Bool, signed int, unsigned int, or some other
    > >>>   implementation-defined type.

    >
    > >>> which, if violated would make your program undefined and would require
    > >>> a diagnostic.  However, from the wording it would seem that an
    > >>> implementation that documents the possibility of using an enum, may
    > >>> accept this code without saying a word.

    >
    > >> So in effect, it may or may not be a constraint violation, depending on
    > >> whether the underlying type of the enum is int, unsigned int or
    > >> something else?

    >
    > > No - the underlying type of the enum is irrelevant. [...]

    >
    > > Of course, portable code should only use the types that are guaranteed
    > > to be allowed.

    >
    > James
    >
    > I think you may have misunderstood what I was saying.
    >
    > My point was that if the enum type is an alias for int, then that is one
    > of the allowed types for a bitfield with no need for any implementation
    > documentation.


    An enum type is never an alias for int. If the underlying type is int,
    then the enum type is compatible with int, but it is still a different
    type, in much the same way that int[] and int[3] are compatible but
    different types. Does this affect programs aside from bit-fields? I
    believe so:

    #include <limits.h>
    enum INT1 { MIN1 = INT_MIN, MAX1 = INT_MAX }; /* Assume INT1 is
    compatible with int */
    enum INT2 { MIN2 = INT_MIN, MAX2 = INT_MAX }; /* Assume INT2 is
    compatible with int too */

    int a;
    enum INT1 a; /* Valid. int and enum INT1 are compatible */

    int b;
    enum INT2 b; /* Also valid. int and enum INT2 are compatible */

    enum INT1 c;
    enum INT2 c; /* Constraint violation. enum INT1 and enum INT2 are not
    compatible. */

    Actually, this is something that the usually strictest compiler I have
    gets wrong, which accepts even the last declaration. GCC and ICC get
    it right and reject it.
    Harald van Dijk, Oct 1, 2011
    #11
  12. Quentin Pope

    James Kuyper Guest

    On 10/01/2011 05:21 PM, Quentin Pope wrote:
    > On Sat, 01 Oct 2011 06:37:23 -0400, James Kuyper wrote:
    >
    >> On 10/01/2011 04:59 AM, Quentin Pope wrote:
    >>> On Thu, 29 Sep 2011 22:11:18 +0100, Ben Bacarisse wrote:
    >>>
    >>>> Quentin Pope <> writes:

    ....
    >>>> Yes, it does. There is a constraint:
    >>>>
    >>>> A bit-field shall have a type that is a qualified or unqualified
    >>>> version of _Bool, signed int, unsigned int, or some other
    >>>> implementation-defined type.
    >>>>
    >>>> which, if violated would make your program undefined and would require
    >>>> a diagnostic. However, from the wording it would seem that an
    >>>> implementation that documents the possibility of using an enum, may
    >>>> accept this code without saying a word.
    >>>
    >>> So in effect, it may or may not be a constraint violation, depending on
    >>> whether the underlying type of the enum is int, unsigned int or
    >>> something else?

    >>
    >> No - the underlying type of the enum is irrelevant. What is relevant is
    >> the implementation's documentation: any additional types that the
    >> documentation says are acceptable may be used. Since "A bit-field is
    >> interpreted as a signed or unsigned integer type" (6.7.2.1p9), it
    >> wouldn't make much sense for an implementation to accept non-integral
    >> types. However, as far as the constraint listed above is concerned, if
    >> an implementation were to document that it accepts 'double' as a type
    >> for a bit-field, then even "double f:16" would not be a violation of the
    >> constraint listed above.
    >>
    >> Of course, portable code should only use the types that are guaranteed
    >> to be allowed.

    >
    > James
    >


    > I think you may have misunderstood what I was saying.


    Apparently.

    > My point was that if the enum type is an alias for int, then that is one


    An enum type is not an alias for an int. In C, types are aliased only
    through the typedef mechanism. Every enumerated type is required to be
    "compatible with char, a signed integer type, or an
    unsigned integer type" (6.7.2.2p4), but compatible types are not aliases
    for each other. The standard often allow one type to be used in place of
    a compatible type, but that's only true when the standard explicitly
    says so; this is not one of those cases.

    > of the allowed types for a bitfield with no need for any implementation
    > documentation.


    I didn't realize that this was the point you were making, in part
    because your point is incorrect. An enumerated type that's compatible
    with 'int' does not qualify as actually being an 'int' for this purpose
    (except insofar as a particular implementation allows it).

    > So although the code won't be portable to every implementation, it will
    > still be portable (no constraint violation) for all implementations where
    > enums have type int.


    A conforming implementation could make your enumeration compatible with
    signed int, and still refuse to compile such a program by reason of
    violating that constraint.
    --
    James Kuyper
    James Kuyper, Oct 1, 2011
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. -

    enum within an enum

    -, Jun 12, 2005, in forum: Java
    Replies:
    6
    Views:
    523
  2. Jerminia
    Replies:
    3
    Views:
    612
    Roedy Green
    Oct 7, 2005
  3. Ernst Murnleitner

    How to enum an enum?

    Ernst Murnleitner, Nov 12, 2003, in forum: C++
    Replies:
    5
    Views:
    440
    Rolf Magnus
    Nov 13, 2003
  4. mrhicks
    Replies:
    2
    Views:
    401
    Dave Thompson
    Jun 10, 2004
  5. Randy
    Replies:
    1
    Views:
    508
    David Harmon
    Jan 7, 2006
Loading...

Share This Page