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


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

Re: Microcontroller software stacks (was Re: this girl calls c ugly)

Started byTim Rentsch <tr.17687@z991.linuxsc.com>
First post2026-06-21 14:13 -0700
Last post2026-08-20 04:51 +0800
Articles 20 on this page of 51 — 10 participants

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

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Microcontroller software stacks (was Re: this girl calls c ugly) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-21 14:13 -0700
    Re: Microcontroller software stacks (was Re: this girl calls c ugly) David Brown <david.brown@hesbynett.no> - 2026-06-22 08:58 +0200
      Re: Microcontroller software stacks (was Re: this girl calls c ugly) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-22 03:35 -0700
        Re: Microcontroller software stacks (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-22 10:50 +0000
        Re: Microcontroller software stacks (was Re: this girl calls c ugly) David Brown <david.brown@hesbynett.no> - 2026-06-22 12:59 +0200
        Storage needed when there are bit-field members Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-28 09:42 -0700
          Re: Storage needed when there are bit-field members Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-28 18:06 -0700
            Re: Storage needed when there are bit-field members Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-28 20:20 -0700
              Re: Storage needed when there are bit-field members Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-08-14 14:56 -0700
                Re: Storage needed when there are bit-field members scott@slp53.sl.home (Scott Lurndal) - 2026-08-14 22:30 +0000
                  Re: Storage needed when there are bit-field members Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-08-15 16:10 -0700
                    Re: Storage needed when there are bit-field members scott@slp53.sl.home (Scott Lurndal) - 2026-08-16 15:20 +0000
              Re: Storage needed when there are bit-field members antispam@fricas.org (Waldek Hebisch) - 2026-08-19 19:34 +0000
                Re: Storage needed when there are bit-field members Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-08-19 15:26 -0700
                  Re: Storage needed when there are bit-field members David Brown <david.brown@hesbynett.no> - 2026-08-20 11:00 +0200
                    Re: Storage needed when there are bit-field members Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-08-20 03:30 -0700
                      Re: Storage needed when there are bit-field members David Brown <david.brown@hesbynett.no> - 2026-08-20 13:58 +0200
                        Re: Storage needed when there are bit-field members Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-08-20 13:37 -0700
                    Re: Storage needed when there are bit-field members Michael S <already5chosen@yahoo.com> - 2026-08-21 14:31 +0300
                      Re: Storage needed when there are bit-field members David Brown <david.brown@hesbynett.no> - 2026-08-21 13:41 +0200
                        Re: Storage needed when there are bit-field members scott@slp53.sl.home (Scott Lurndal) - 2026-08-21 15:41 +0000
                      Re: Storage needed when there are bit-field members Michael S <already5chosen@yahoo.com> - 2026-08-21 14:58 +0300
                  Re: Storage needed when there are bit-field members scott@slp53.sl.home (Scott Lurndal) - 2026-08-20 14:50 +0000
                    Re: Storage needed when there are bit-field members "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-08-20 12:31 -0700
                    Re: Storage needed when there are bit-field members antispam@fricas.org (Waldek Hebisch) - 2026-08-20 19:55 +0000
                      Re: Storage needed when there are bit-field members David Brown <david.brown@hesbynett.no> - 2026-08-21 08:57 +0200
                        Re: Storage needed when there are bit-field members scott@slp53.sl.home (Scott Lurndal) - 2026-08-21 14:59 +0000
                  Re: Storage needed when there are bit-field members Michael S <already5chosen@yahoo.com> - 2026-08-20 22:15 +0300
            Re: Storage needed when there are bit-field members Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-08-14 14:19 -0700
    Re: Microcontroller software stacks (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-22 10:45 +0000
      Re: Microcontroller software stacks (was Re: this girl calls c ugly) scott@slp53.sl.home (Scott Lurndal) - 2026-06-22 15:23 +0000
      Re: Microcontroller software stacks (was Re: this girl calls c ugly) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-08-14 13:23 -0700
        Re: Microcontroller software stacks (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-08-18 20:32 +0000
    Re: Microcontroller software stacks (was Re: this girl calls c ugly) scott@slp53.sl.home (Scott Lurndal) - 2026-06-22 15:04 +0000
      Re: Microcontroller software stacks (was Re: this girl calls c ugly) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-22 13:02 -0700
      Re: Microcontroller software stacks Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-08-14 12:51 -0700
        Re: Microcontroller software stacks Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-08-15 05:02 +0800
          Re: Microcontroller software stacks bart <bc@freeuk.com> - 2026-08-15 01:18 +0100
            Re: Microcontroller software stacks Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-08-16 13:52 +0800
        Re: Microcontroller software stacks Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-08-14 14:06 -0700
        Re: Microcontroller software stacks scott@slp53.sl.home (Scott Lurndal) - 2026-08-14 21:42 +0000
          Re: Microcontroller software stacks Michael S <already5chosen@yahoo.com> - 2026-08-15 22:13 +0300
            Re: Microcontroller software stacks scott@slp53.sl.home (Scott Lurndal) - 2026-08-15 19:39 +0000
              Re: Microcontroller software stacks Michael S <already5chosen@yahoo.com> - 2026-08-15 23:22 +0300
                Re: Microcontroller software stacks scott@slp53.sl.home (Scott Lurndal) - 2026-08-16 14:38 +0000
                  Re: Microcontroller software stacks Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-08-16 16:11 -0700
          Re: Microcontroller software stacks Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-08-15 16:16 -0700
            Re: Microcontroller software stacks cross@spitfire.i.gajendra.net (Dan Cross) - 2026-08-18 20:34 +0000
            Re: Microcontroller software stacks antispam@fricas.org (Waldek Hebisch) - 2026-08-19 19:57 +0000
          Re: Microcontroller software stacks Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-08-15 17:31 -0700
    Re: Microcontroller software stacks (was Re: this girl calls c ugly) Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-08-20 04:51 +0800

Page 1 of 3  [1] 2 3  Next page →


#400174 — Re: Microcontroller software stacks (was Re: this girl calls c ugly)

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-06-21 14:13 -0700
SubjectRe: Microcontroller software stacks (was Re: this girl calls c ugly)
Message-ID<86h5mv8umk.fsf@linuxsc.com>
scott@slp53.sl.home (Scott Lurndal) writes:

> One might also define data structures for control and status
> registers using bitfield structs.

Yeah.  This kind of application (among others) I consider one of
the motivating forces behind bitfields.

[Some whitespace trimming done in the excerpt below.]

> e.g. for the SATA UAHC_GLB_OOBR register:
>
> union UAHC_GBL_OOBR {
>   uint32_t u;
>   struct UAHC_GBL_OOBR_s {
> #if __BYTE_ORDER == __BIG_ENDIAN
>     uint32_t we     :  1; /**< R/W/H - Write enable. */
>     uint32_t cwmin  :  7; /**< R/W/H - COMWAKE minimum value [...] */
>     uint32_t cwmax  :  8; /**< R/W/H - COMWAKE maximum value [...] */
>     uint32_t cimin  :  8; /**< R/W/H - COMINIT minimum value [...] */
>     uint32_t cimax  :  8; /**< R/W/H - COMINIT maximum value [...] */
> #else
>     uint32_t cimax  :  8;
>     uint32_t cimin  :  8;
>     uint32_t cwmax  :  8;
>     uint32_t cwmin  :  7;
>     uint32_t we     :  1;
> #endif
>   } s;
> };

To me it seems kind of goofy to use uint32_t for the bitfields type.
I would just use unsigned, which is just as sure to work as intended,
isn't it?

(Personal note:  I tried sending an email to you at the address in
your news posting, but my mailer complained about the address.  If
it's okay could I ask you to send me an email at the address in my
news posting?  Whatever you decide, thanks.)

[toc] | [next] | [standalone]


#400184

FromDavid Brown <david.brown@hesbynett.no>
Date2026-06-22 08:58 +0200
Message-ID<111amdq$1at39$1@dont-email.me>
In reply to#400174
On 21/06/2026 23:13, Tim Rentsch wrote:
> scott@slp53.sl.home (Scott Lurndal) writes:
> 
>> One might also define data structures for control and status
>> registers using bitfield structs.
> 
> Yeah.  This kind of application (among others) I consider one of
> the motivating forces behind bitfields.
> 
> [Some whitespace trimming done in the excerpt below.]
> 
>> e.g. for the SATA UAHC_GLB_OOBR register:
>>
>> union UAHC_GBL_OOBR {
>>    uint32_t u;
>>    struct UAHC_GBL_OOBR_s {
>> #if __BYTE_ORDER == __BIG_ENDIAN
>>      uint32_t we     :  1; /**< R/W/H - Write enable. */
>>      uint32_t cwmin  :  7; /**< R/W/H - COMWAKE minimum value [...] */
>>      uint32_t cwmax  :  8; /**< R/W/H - COMWAKE maximum value [...] */
>>      uint32_t cimin  :  8; /**< R/W/H - COMINIT minimum value [...] */
>>      uint32_t cimax  :  8; /**< R/W/H - COMINIT maximum value [...] */
>> #else
>>      uint32_t cimax  :  8;
>>      uint32_t cimin  :  8;
>>      uint32_t cwmax  :  8;
>>      uint32_t cwmin  :  7;
>>      uint32_t we     :  1;
>> #endif
>>    } s;
>> };
> 
> To me it seems kind of goofy to use uint32_t for the bitfields type.
> I would just use unsigned, which is just as sure to work as intended,
> isn't it?
> 

Size-specific types are almost always the best choice for situations 
like this.

When you are using bitfields simply as a way to pack small bits of data 
more efficiently, you use whatever style of type fits best with your 
needs - consistency with the rest of the code, making the sizes 
independent of the target, making the sizes adjust according to the 
target, maximal portability across compilers and standards version - 
whatever you like.

But when you are using them to fit to an existing externally defined 
structure, fixed-size types are a big advantage (for the whole struct, 
not just the bitfields).  It is easier to see that the structure is 
correct because you are explicit about the sizes.  Types like "uint32_t" 
have the advantage that they are not portable to targets that can't 
support them - as it is likely that you would need to write such code 
somewhat differently for it to work on a machine that does not have such 
types, causing a compile-time error is useful.

And when the structures represent hardware registers, such as here, you 
have additional motivation - these registers are typically accessed with 
volatile accesses, and you often want to be sure of the exact size of 
the accesses.  That is always up to the implementation, but the norm is 
that when your bitfields are of a given size, generated volatile 
accesses for them use that matching size.

So "uint32_t" says /precisely/ what the code author wants to say for the 
type.  "unsigned" does not.  "uint32_t" is appropriate regardless of the 
target and the choice of standard integer sizes - "unsigned" is not.

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


#400186

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-06-22 03:35 -0700
Message-ID<111b35d$1duuq$1@kst.eternal-september.org>
In reply to#400184
David Brown <david.brown@hesbynett.no> writes:
> On 21/06/2026 23:13, Tim Rentsch wrote:
>> scott@slp53.sl.home (Scott Lurndal) writes:
>>> One might also define data structures for control and status
>>> registers using bitfield structs.
>> Yeah.  This kind of application (among others) I consider one of
>> the motivating forces behind bitfields.
>> [Some whitespace trimming done in the excerpt below.]
>> 
>>> e.g. for the SATA UAHC_GLB_OOBR register:
>>>
>>> union UAHC_GBL_OOBR {
>>>    uint32_t u;
>>>    struct UAHC_GBL_OOBR_s {
>>> #if __BYTE_ORDER == __BIG_ENDIAN
>>>      uint32_t we     :  1; /**< R/W/H - Write enable. */
>>>      uint32_t cwmin  :  7; /**< R/W/H - COMWAKE minimum value [...] */
>>>      uint32_t cwmax  :  8; /**< R/W/H - COMWAKE maximum value [...] */
>>>      uint32_t cimin  :  8; /**< R/W/H - COMINIT minimum value [...] */
>>>      uint32_t cimax  :  8; /**< R/W/H - COMINIT maximum value [...] */
>>> #else
>>>      uint32_t cimax  :  8;
>>>      uint32_t cimin  :  8;
>>>      uint32_t cwmax  :  8;
>>>      uint32_t cwmin  :  7;
>>>      uint32_t we     :  1;
>>> #endif
>>>    } s;
>>> };
>> To me it seems kind of goofy to use uint32_t for the bitfields type.
>> I would just use unsigned, which is just as sure to work as intended,
>> isn't it?
>> 
>
> Size-specific types are almost always the best choice for situations
> like this.
>
> When you are using bitfields simply as a way to pack small bits of
> data more efficiently, you use whatever style of type fits best with
> your needs - consistency with the rest of the code, making the sizes
> independent of the target, making the sizes adjust according to the
> target, maximal portability across compilers and standards version -
> whatever you like.
>
> But when you are using them to fit to an existing externally defined
> structure, fixed-size types are a big advantage (for the whole struct,
> not just the bitfields).  It is easier to see that the structure is
> correct because you are explicit about the sizes.  Types like
> "uint32_t" have the advantage that they are not portable to targets
> that can't support them - as it is likely that you would need to write
> such code somewhat differently for it to work on a machine that does
> not have such types, causing a compile-time error is useful.
>
> And when the structures represent hardware registers, such as here,
> you have additional motivation - these registers are typically
> accessed with volatile accesses, and you often want to be sure of the
> exact size of the accesses.  That is always up to the implementation,
> but the norm is that when your bitfields are of a given size,
> generated volatile accesses for them use that matching size.
>
> So "uint32_t" says /precisely/ what the code author wants to say for
> the type.  "unsigned" does not.  "uint32_t" is appropriate regardless
> of the target and the choice of standard integer sizes - "unsigned" is
> not.

    uint32_t x;
says precisely that x is 32 bits, unsigned, with no padding bits.  But
    uint32_t bf : 1;
is meaningfully different from
    unsigned bf : 1;
only because in most implementations (and ABIs), the underlying type of
a bit field affects the layout of the entire structure.

I accept that this is the case, but it's never made any sense to me, and
there's no hint of it in the C standard.

For example, if I write:
    uint64_t bf : 1;
then the containing struct is typically at least 64 bits, even though
those other 63 bits aren't part of the bit field and other members can
be allocated within them.

It would make a lot more sense *to me* if an N-bit bit field were simply
N bits.

(And of course int, signed int, unsigned int, and bool are the only
portable types for bitfields -- but if you're using bit fields, it's
likely that portability isn't your only priority.)

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

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


#400188

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2026-06-22 10:50 +0000
Message-ID<111b412$41p$1@reader1.panix.com>
In reply to#400186
In article <111b35d$1duuq$1@kst.eternal-september.org>,
Keith Thompson  <Keith.S.Thompson+u@gmail.com> wrote:
>[snip]
>    uint32_t x;
>says precisely that x is 32 bits, unsigned, with no padding bits.  But
>    uint32_t bf : 1;
>is meaningfully different from
>    unsigned bf : 1;
>only because in most implementations (and ABIs), the underlying type of
>a bit field affects the layout of the entire structure.
>
>I accept that this is the case, but it's never made any sense to me, and
>there's no hint of it in the C standard.
>
>For example, if I write:
>    uint64_t bf : 1;
>then the containing struct is typically at least 64 bits, even though
>those other 63 bits aren't part of the bit field and other members can
>be allocated within them.
>
>It would make a lot more sense *to me* if an N-bit bit field were simply
>N bits.

If dealing with, e.g., hardware, then the author should probably
constrain things so that bitfields occupy the fully width of the
underlying type.  E.g.,

    uint64_t bt:1;
    uint64_t reserved:63;

And so forth.

>(And of course int, signed int, unsigned int, and bool are the only
>portable types for bitfields -- but if you're using bit fields, it's
>likely that portability isn't your only priority.)

It may be, but you'll be programming against an ABI (or set of
ABIs) or similar external standards that give you stronger
guarantees than ISO C, at that point.

	- Dan C.

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


#400189

FromDavid Brown <david.brown@hesbynett.no>
Date2026-06-22 12:59 +0200
Message-ID<111b4if$1dtp4$1@dont-email.me>
In reply to#400186
On 22/06/2026 12:35, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 21/06/2026 23:13, Tim Rentsch wrote:
>>> scott@slp53.sl.home (Scott Lurndal) writes:
>>>> One might also define data structures for control and status
>>>> registers using bitfield structs.
>>> Yeah.  This kind of application (among others) I consider one of
>>> the motivating forces behind bitfields.
>>> [Some whitespace trimming done in the excerpt below.]
>>>
>>>> e.g. for the SATA UAHC_GLB_OOBR register:
>>>>
>>>> union UAHC_GBL_OOBR {
>>>>     uint32_t u;
>>>>     struct UAHC_GBL_OOBR_s {
>>>> #if __BYTE_ORDER == __BIG_ENDIAN
>>>>       uint32_t we     :  1; /**< R/W/H - Write enable. */
>>>>       uint32_t cwmin  :  7; /**< R/W/H - COMWAKE minimum value [...] */
>>>>       uint32_t cwmax  :  8; /**< R/W/H - COMWAKE maximum value [...] */
>>>>       uint32_t cimin  :  8; /**< R/W/H - COMINIT minimum value [...] */
>>>>       uint32_t cimax  :  8; /**< R/W/H - COMINIT maximum value [...] */
>>>> #else
>>>>       uint32_t cimax  :  8;
>>>>       uint32_t cimin  :  8;
>>>>       uint32_t cwmax  :  8;
>>>>       uint32_t cwmin  :  7;
>>>>       uint32_t we     :  1;
>>>> #endif
>>>>     } s;
>>>> };
>>> To me it seems kind of goofy to use uint32_t for the bitfields type.
>>> I would just use unsigned, which is just as sure to work as intended,
>>> isn't it?
>>>
>>
>> Size-specific types are almost always the best choice for situations
>> like this.
>>
>> When you are using bitfields simply as a way to pack small bits of
>> data more efficiently, you use whatever style of type fits best with
>> your needs - consistency with the rest of the code, making the sizes
>> independent of the target, making the sizes adjust according to the
>> target, maximal portability across compilers and standards version -
>> whatever you like.
>>
>> But when you are using them to fit to an existing externally defined
>> structure, fixed-size types are a big advantage (for the whole struct,
>> not just the bitfields).  It is easier to see that the structure is
>> correct because you are explicit about the sizes.  Types like
>> "uint32_t" have the advantage that they are not portable to targets
>> that can't support them - as it is likely that you would need to write
>> such code somewhat differently for it to work on a machine that does
>> not have such types, causing a compile-time error is useful.
>>
>> And when the structures represent hardware registers, such as here,
>> you have additional motivation - these registers are typically
>> accessed with volatile accesses, and you often want to be sure of the
>> exact size of the accesses.  That is always up to the implementation,
>> but the norm is that when your bitfields are of a given size,
>> generated volatile accesses for them use that matching size.
>>
>> So "uint32_t" says /precisely/ what the code author wants to say for
>> the type.  "unsigned" does not.  "uint32_t" is appropriate regardless
>> of the target and the choice of standard integer sizes - "unsigned" is
>> not.
> 
>      uint32_t x;
> says precisely that x is 32 bits, unsigned, with no padding bits.  But
>      uint32_t bf : 1;
> is meaningfully different from
>      unsigned bf : 1;
> only because in most implementations (and ABIs), the underlying type of
> a bit field affects the layout of the entire structure.
> 
> I accept that this is the case, but it's never made any sense to me, and
> there's no hint of it in the C standard.
> 
> For example, if I write:
>      uint64_t bf : 1;
> then the containing struct is typically at least 64 bits, even though
> those other 63 bits aren't part of the bit field and other members can
> be allocated within them.
> 
> It would make a lot more sense *to me* if an N-bit bit field were simply
> N bits.

There is sense in that, yes, but as I said the access type is important 
too.  The struct Scott gave would not be the same if it used uint8_t 
instead of uint32_t for the bit-fields, even though there would be no 
difference in the alignments or paddings (on a "normal" cpus, rather 
than a DS9000).  For hardware registers, access size is often critical - 
it is not like accessing ram.  And while the choice of access size is 
implementation defined, the size of the type used for the bit-field is 
the most common way to determine that (for volatile accesses).

If C had a different way of specifying access sizes, then it might be a 
bit different - perhaps _BitInt types would be the best choices for 
bit-field types.

> 
> (And of course int, signed int, unsigned int, and bool are the only
> portable types for bitfields -- but if you're using bit fields, it's
> likely that portability isn't your only priority.)
> 

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


#400273 — Storage needed when there are bit-field members

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-06-28 09:42 -0700
SubjectStorage needed when there are bit-field members
Message-ID<86v7b27h20.fsf_-_@linuxsc.com>
In reply to#400186
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

[...]

>     uint32_t x;
> says precisely that x is 32 bits, unsigned, with no padding bits.

Actually it says a little bit more, but never mind that.

> But
>     uint32_t bf : 1;
> is meaningfully different from
>     unsigned bf : 1;

> only because in most implementations (and ABIs), the underlying type
> of a bit field affects the layout of the entire structure.

I would say this differently.  The two member declarations shown
might be meaningfully different, depending on the implementation:
they >can< be different, but they don't have to be, and indeed on
many implementations they are exactly the same.

> I accept that this is the case, but it's never made any sense to me,
> and there's no hint of it in the C standard.

I think saying there is not even a hint is an overstatement.  The C
standard says that an implementation "may allocate any addressable
storage unit large enough to hold a bit-field."  It shouldn't be a
surprise that how much storage is allocated depends on the type of
the bit-field member.  For example, a bit-field of type 'unsigned'
might very well choose a larger storage unit than what is chosen
for a bit-field of type '_Bool'.  It seems obvious that the type of
a bit-field might affect what size and layout is chosen.

> For example, if I write:
>     uint64_t bf : 1;

> then the containing struct is typically at least 64 bits, even
> though those other 63 bits aren't part of the bit field and other
> members can be allocated within them.
>
> It would make a lot more sense *to me* if an N-bit bit field were
> simply N bits.

Two problems with that.  One, it seems to be in conflict with what
the C standard says about 0-width bit-fields.  Two, the C standard
explicitly allows allocating bit-fields using a high-to-low order or
a low-to-high order (implementation-defined choice).  Presumably
this freedom is given to accommodate both big- and little-endian
platforms.  The idea that an N-bit bit-field should simply be N bits
doesn't work in big-endian environments.  It seems better to allow
little-endian implementations to choose a size that matches what a
big-endian implementation would use, rather than insisting that they
be different.

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


#400276 — Re: Storage needed when there are bit-field members

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-06-28 18:06 -0700
SubjectRe: Storage needed when there are bit-field members
Message-ID<111sgeq$3vq40$1@kst.eternal-september.org>
In reply to#400273
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
[...]
>> But
>>     uint32_t bf : 1;
>> is meaningfully different from
>>     unsigned bf : 1;
>
>> only because in most implementations (and ABIs), the underlying type
>> of a bit field affects the layout of the entire structure.
[...]
>> I accept that this is the case, but it's never made any sense to me,
>> and there's no hint of it in the C standard.
>
> I think saying there is not even a hint is an overstatement.  The C
> standard says that an implementation "may allocate any addressable
> storage unit large enough to hold a bit-field."  It shouldn't be a
> surprise that how much storage is allocated depends on the type of
> the bit-field member.  For example, a bit-field of type 'unsigned'
> might very well choose a larger storage unit than what is chosen
> for a bit-field of type '_Bool'.  It seems obvious that the type of
> a bit-field might affect what size and layout is chosen.

I'm sure it seems obvious to you.  As I said, it's not at all
obvious to me.

Prior to C99, C didn't even require compilers to support bit-field types
other than int, unsigned int, and signed int.  The declared type might
typically be used only to determine the signedness of the bit-field
(though I *think* most compilers permitted other types).

Implementations are certainly not *required* to use the declared
type of a bit-field as a factor in deciding how to allocate it,
or how to allocate the rest of the structure.  Allocating just one
byte for an isolated 1-bit bit-field of any declared type would
be conforming.  A conforming compiler could use the declared type
only to determine the signedness and the maximum allowed width of
a bit-field (and its conversion behavior in the case of bool)

>> For example, if I write:
>>     uint64_t bf : 1;
>
>> then the containing struct is typically at least 64 bits, even
>> though those other 63 bits aren't part of the bit field and other
>> members can be allocated within them.
>>
>> It would make a lot more sense *to me* if an N-bit bit field were
>> simply N bits.
>
> Two problems with that.  One, it seems to be in conflict with what
> the C standard says about 0-width bit-fields.

0-width bit-fields are obviously a special case.

>                                                Two, the C standard
> explicitly allows allocating bit-fields using a high-to-low order or
> a low-to-high order (implementation-defined choice).  Presumably
> this freedom is given to accommodate both big- and little-endian
> platforms.  The idea that an N-bit bit-field should simply be N bits
> doesn't work in big-endian environments.  It seems better to allow
> little-endian implementations to choose a size that matches what a
> big-endian implementation would use, rather than insisting that they
> be different.

I honestly don't understand your point here.  How does making
N-bit bit-fields N bits not work in a big-endian environment?
Can you elaborate?  Of course endianness can affect how bit-fields
are allocated within a "storage unit".

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

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


#400280 — Re: Storage needed when there are bit-field members

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-06-28 20:20 -0700
SubjectRe: Storage needed when there are bit-field members
Message-ID<111soae$1eq8$1@kst.eternal-september.org>
In reply to#400276
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
[...]
>>> It would make a lot more sense *to me* if an N-bit bit field were
>>> simply N bits.
[...]
>>                                                Two, the C standard
>> explicitly allows allocating bit-fields using a high-to-low order or
>> a low-to-high order (implementation-defined choice).  Presumably
>> this freedom is given to accommodate both big- and little-endian
>> platforms.  The idea that an N-bit bit-field should simply be N bits
>> doesn't work in big-endian environments.  It seems better to allow
>> little-endian implementations to choose a size that matches what a
>> big-endian implementation would use, rather than insisting that they
>> be different.
>
> I honestly don't understand your point here.  How does making
> N-bit bit-fields N bits not work in a big-endian environment?
> Can you elaborate?  Of course endianness can affect how bit-fields
> are allocated within a "storage unit".

Perhaps you read more than I intended into my statement about N-bit
bit-fields being "simply N bits".

Thinking about this a bit more.

As of C90, "A bit-field shall have a type that is a qualified or
unqualified version of one of int, unsigned int, or signed int."
The "shall" is outside a constraint, so an implementation could allow
bit-fields of other types without triggering a required diagnostic,
and many implementations did so.

C99 added _Bool bit-fields, and explicitly allowed "some other
implementation-defined type".  C23 allows bit-fields of bit-precise
integer types; I'll avoid thinking about that for now.

Implementions commonly use the declared type of a bit-field to
affect the layout, not necessarily of the bit-field itself, but
of the containing structure.  Given that the standard doesn't
require support for types other than bool and the int types (and
now bit-precise integer types), the idea that `short bf:1` and
`long bf:1` have different semantics is not, as far as I can tell,
implied by anything in the standard.

I understand that implementations *can* allow other integer types
in bit-field declarations, and that they can use the declared type
in implementation-defined ways.

One possible approach would be to use the declared type only to
determine the signedness of the bit-field (and its conversion
behavior in the case of bool), and the upper bound for the number
of bits (`int bf:33` is a constraint violation if int is 32 bits).
In this relatively simple approach, there's no point in defining
a bit-field with one of the char or short types.

Using gcc on Linux, if I define a 1-bit bit-field with a 64-bit type,
that forces the containing structure to be at least 64 bits -- but
not by reserving a 64-bit region to hold the bit-field.  If I define
a struct containing a 1-bit unsigned long long bit-field followed by
a 1-byte ordinary member, the second member is at a 1-bytes offset.

I had gotten the impression that the behavior is imposed by ABIs,
but my copy of the "System V Application Binary Interface AMD64
Architecture Processor Supplement" just says:

    - bit-fields are allocated from right to left
    - bit-fields must be contained in a storage unit appropriate for
      its declared type
    - bit-fields may share a storage unit with other struct / union
      members

which doesn't seem to be enough to specify the behavior I see
(and I find it annoyingly vague).

Is there a document (ABI, compiler document, whatever) that specifies
the (odd, to me) behavior I'm seeing?

Here's a test program:

#include <stdio.h>
#include <stddef.h>
int main(void) {
    struct s1 { unsigned char bf:1;      unsigned char c; };
    struct s2 { unsigned short bf:1;     unsigned char c; };
    struct s3 { unsigned int bf:1;       unsigned char c; };
    struct s4 { unsigned long bf:1;      unsigned char c; };
    struct s5 { unsigned long long bf:1; unsigned char c; };

    printf("%-18s %-4s %-6s %s\n",
           "type", "size", "offset", "struct-size");

    printf("%-18s %-4zu %-6zu %-1zu\n",
           "unsigned char",
           sizeof (unsigned char),
           offsetof(struct s1, c),
           sizeof (struct s1));
    printf("%-18s %-4zu %-6zu %-1zu\n",
           "unsigned short",
           sizeof (unsigned short),
           offsetof(struct s2, c),
           sizeof (struct s2));
    printf("%-18s %-4zu %-6zu %-1zu\n",
           "unsigned int",
           sizeof (unsigned int),
           offsetof(struct s3, c),
           sizeof (struct s3));
    printf("%-18s %-4zu %-6zu %-1zu\n",
           "unsigned long",
           sizeof (unsigned long),
           offsetof(struct s4, c),
           sizeof (struct s4));
    printf("%-18s %-4zu %-6zu %-1zu\n",
           "unsigned long long",
           sizeof (unsigned long long),
           offsetof(struct s5, c),
           sizeof (struct s5));
}

and its output on my system (Ubuntu, x86_64):

type               size offset struct-size
unsigned char      1    1      2
unsigned short     2    1      2
unsigned int       4    1      4
unsigned long      8    1      8
unsigned long long 8    1      8

Again, the declared type of a bit-field doesn't affect how the
bit-field itself is allocated, but it does affect the size of the
containing struct, but it doesn't prevent other members from being
allocated within that space.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

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


#401191 — Re: Storage needed when there are bit-field members

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-08-14 14:56 -0700
SubjectRe: Storage needed when there are bit-field members
Message-ID<86o6f45pu7.fsf@linuxsc.com>
In reply to#400280
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>
>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>>
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>
> [...]
>
>>>> It would make a lot more sense *to me* if an N-bit bit field were
>>>> simply N bits.
>
> [...]
>
>>>                                                Two, the C standard
>>> explicitly allows allocating bit-fields using a high-to-low order or
>>> a low-to-high order (implementation-defined choice).  Presumably
>>> this freedom is given to accommodate both big- and little-endian
>>> platforms.  The idea that an N-bit bit-field should simply be N bits
>>> doesn't work in big-endian environments.  It seems better to allow
>>> little-endian implementations to choose a size that matches what a
>>> big-endian implementation would use, rather than insisting that they
>>> be different.
>>
>> I honestly don't understand your point here.  How does making
>> N-bit bit-fields N bits not work in a big-endian environment?
>> Can you elaborate?  Of course endianness can affect how bit-fields
>> are allocated within a "storage unit".
>
> Perhaps you read more than I intended into my statement about N-bit
> bit-fields being "simply N bits".

It's possible, but I don't think I did.

> Thinking about this a bit more.
>
> As of C90, "A bit-field shall have a type that is a qualified or
> unqualified version of one of int, unsigned int, or signed int."
> The "shall" is outside a constraint, so an implementation could allow
> bit-fields of other types without triggering a required diagnostic,
> and many implementations did so.

Allowing other types is listed as a common extension.

> C99 added _Bool bit-fields, and explicitly allowed "some other
> implementation-defined type".  C23 allows bit-fields of bit-precise
> integer types;  I'll avoid thinking about that for now.
>
> Implementions commonly use the declared type of a bit-field to
> affect the layout, not necessarily of the bit-field itself, but
> of the containing structure.  Given that the standard doesn't
> require support for types other than bool and the int types (and
> now bit-precise integer types), the idea that `short bf:1` and
> `long bf:1` have different semantics is not, as far as I can tell,
> implied by anything in the standard.

They may have different semantics, depending on what particular
implementation-specific choices are made, but as best I can tell
the C standard doesn't require them to.

> I understand that implementations *can* allow other integer types
> in bit-field declarations, and that they can use the declared type
> in implementation-defined ways.

I don't think there is a specific explicit requirement that how a
bit-field's declared type affects layout be implementation-defined.
There is a general requirement that the number, order, and encodings
of bytes that make up an object be implementation-defined if they
are not explicitly specified.

> One possible approach would be to use the declared type only to
> determine the signedness of the bit-field (and its conversion
> behavior in the case of bool), and the upper bound for the number
> of bits (`int bf:33` is a constraint violation if int is 32 bits).
> In this relatively simple approach, there's no point in defining
> a bit-field with one of the char or short types.

I think that depends on how the allocatable storage unit for a
given bit-field is chosen.  The C standard is pretty vague about
what determines what allocatable storage unit is chosen in each
case, and under what circumstances that might vary from bit-field
to bit-field.

> Using gcc on Linux, if I define a 1-bit bit-field with a 64-bit type,
> that forces the containing structure to be at least 64 bits -- but
> not by reserving a 64-bit region to hold the bit-field.  If I define
> a struct containing a 1-bit unsigned long long bit-field followed by
> a 1-byte ordinary member, the second member is at a 1-bytes offset.
>
> I had gotten the impression that the behavior is imposed by ABIs,
> but my copy of the "System V Application Binary Interface AMD64
> Architecture Processor Supplement" just says:
>
>     - bit-fields are allocated from right to left

I think that means they are allocated in order of low-to-high,
because the AMD64 architecture is little-endian.

>     - bit-fields must be contained in a storage unit appropriate for
>       its declared type
>     - bit-fields may share a storage unit with other struct / union
>       members
>
> which doesn't seem to be enough to specify the behavior I see
> (and I find it annoyingly vague).
>
> Is there a document (ABI, compiler document, whatever) that specifies
> the (odd, to me) behavior I'm seeing?

As best I can tell the layout you are seeing is consistent with
the rules stated above.  Perhaps the rules are deliberately meant
to be an under-specification (which IMO is not a bad thing).

> Here's a test program:
>
> #include <stdio.h>
> #include <stddef.h>
> int main(void) {
>     struct s1 { unsigned char bf:1;      unsigned char c; };
>     struct s2 { unsigned short bf:1;     unsigned char c; };
>     struct s3 { unsigned int bf:1;       unsigned char c; };
>     struct s4 { unsigned long bf:1;      unsigned char c; };
>     struct s5 { unsigned long long bf:1; unsigned char c; };
>
>     printf("%-18s %-4s %-6s %s\n",
>            "type", "size", "offset", "struct-size");
>
>     printf("%-18s %-4zu %-6zu %-1zu\n",
>            "unsigned char",
>            sizeof (unsigned char),
>            offsetof(struct s1, c),
>            sizeof (struct s1));
>     printf("%-18s %-4zu %-6zu %-1zu\n",
>            "unsigned short",
>            sizeof (unsigned short),
>            offsetof(struct s2, c),
>            sizeof (struct s2));
>     printf("%-18s %-4zu %-6zu %-1zu\n",
>            "unsigned int",
>            sizeof (unsigned int),
>            offsetof(struct s3, c),
>            sizeof (struct s3));
>     printf("%-18s %-4zu %-6zu %-1zu\n",
>            "unsigned long",
>            sizeof (unsigned long),
>            offsetof(struct s4, c),
>            sizeof (struct s4));
>     printf("%-18s %-4zu %-6zu %-1zu\n",
>            "unsigned long long",
>            sizeof (unsigned long long),
>            offsetof(struct s5, c),
>            sizeof (struct s5));
> }
>
> and its output on my system (Ubuntu, x86_64):
>
> type               size offset struct-size
> unsigned char      1    1      2
> unsigned short     2    1      2
> unsigned int       4    1      4
> unsigned long      8    1      8
> unsigned long long 8    1      8
>
> Again, the declared type of a bit-field doesn't affect how the
> bit-field itself is allocated, but it does affect the size of the
> containing struct, but it doesn't prevent other members from being
> allocated within that space.

You should be able to determine the layout exactly from the
implementation's documentation.  If you can't, that means the
implementation is not conforming, because these are implemenation
defined behaviors, and so much be documented.

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


#401192 — Re: Storage needed when there are bit-field members

Fromscott@slp53.sl.home (Scott Lurndal)
Date2026-08-14 22:30 +0000
SubjectRe: Storage needed when there are bit-field members
Message-ID<5GMfS.13614$EDc8.5150@fx24.iad>
In reply to#401191
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>
>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>
>>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>>>
>>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>
>> [...]
>>
>>>>> It would make a lot more sense *to me* if an N-bit bit field were
>>>>> simply N bits.
>>
>> [...]
>>
 <snip>

>> I had gotten the impression that the behavior is imposed by ABIs,
>> but my copy of the "System V Application Binary Interface AMD64
>> Architecture Processor Supplement" just says:
>>
>>     - bit-fields are allocated from right to left
>
>I think that means they are allocated in order of low-to-high,
>because the AMD64 architecture is little-endian.
>
>>     - bit-fields must be contained in a storage unit appropriate for
>>       its declared type
>>     - bit-fields may share a storage unit with other struct / union
>>       members
>>
>> which doesn't seem to be enough to specify the behavior I see
>> (and I find it annoyingly vague).
>>
>> Is there a document (ABI, compiler document, whatever) that specifies
>> the (odd, to me) behavior I'm seeing?
>
>As best I can tell the layout you are seeing is consistent with
>the rules stated above.  Perhaps the rules are deliberately meant
>to be an under-specification (which IMO is not a bad thing).
>
>> Here's a test program:
>>
>> #include <stdio.h>
>> #include <stddef.h>
>> int main(void) {
>>     struct s1 { unsigned char bf:1;      unsigned char c; };
>>     struct s2 { unsigned short bf:1;     unsigned char c; };
>>     struct s3 { unsigned int bf:1;       unsigned char c; };
>>     struct s4 { unsigned long bf:1;      unsigned char c; };
>>     struct s5 { unsigned long long bf:1; unsigned char c; };

FWIW, adding GCC's  __attribute__((packed)) to each of those, we see:

> type               size offset struct-size
> unsigned char      1    1      2
> unsigned short     2    1      2
> unsigned int       4    1      4
> unsigned long      8    1      8
> unsigned long long 8    1      8

type               size offset struct-size
unsigned char      1    1      2
unsigned short     2    1      2
unsigned int       4    1      2
unsigned long      8    1      2
unsigned long long 8    1      2

Which doesn't seem to violate the ABI rules you quoted.

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


#401223 — Re: Storage needed when there are bit-field members

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-08-15 16:10 -0700
SubjectRe: Storage needed when there are bit-field members
Message-ID<86cxvj3rq1.fsf@linuxsc.com>
In reply to#401192
scott@slp53.sl.home (Scott Lurndal) writes:

> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>
>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>>
>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>>>>
>>>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>>
>>> [...]
>>>
>>>>>> It would make a lot more sense *to me* if an N-bit bit field were
>>>>>> simply N bits.
>>>
>>> [...]
>
>  <snip>
>
>>> I had gotten the impression that the behavior is imposed by ABIs,
>>> but my copy of the "System V Application Binary Interface AMD64
>>> Architecture Processor Supplement" just says:
>>>
>>>     - bit-fields are allocated from right to left
>>
>> I think that means they are allocated in order of low-to-high,
>> because the AMD64 architecture is little-endian.
>>
>>>     - bit-fields must be contained in a storage unit appropriate for
>>>       its declared type
>>>     - bit-fields may share a storage unit with other struct / union
>>>       members
>>>
>>> which doesn't seem to be enough to specify the behavior I see
>>> (and I find it annoyingly vague).
>>>
>>> Is there a document (ABI, compiler document, whatever) that specifies
>>> the (odd, to me) behavior I'm seeing?
>>
>> As best I can tell the layout you are seeing is consistent with
>> the rules stated above.  Perhaps the rules are deliberately meant
>> to be an under-specification (which IMO is not a bad thing).
>>
>>> Here's a test program:
>>>
>>> #include <stdio.h>
>>> #include <stddef.h>
>>> int main(void) {
>>>     struct s1 { unsigned char bf:1;      unsigned char c; };
>>>     struct s2 { unsigned short bf:1;     unsigned char c; };
>>>     struct s3 { unsigned int bf:1;       unsigned char c; };
>>>     struct s4 { unsigned long bf:1;      unsigned char c; };
>>>     struct s5 { unsigned long long bf:1; unsigned char c; };
>
> FWIW, adding GCC's  __attribute__((packed)) to each of those, we see:
>
>> type               size offset struct-size
>> unsigned char      1    1      2
>> unsigned short     2    1      2
>> unsigned int       4    1      4
>> unsigned long      8    1      8
>> unsigned long long 8    1      8
>
> type               size offset struct-size
> unsigned char      1    1      2
> unsigned short     2    1      2
> unsigned int       4    1      2
> unsigned long      8    1      2
> unsigned long long 8    1      2
>
> Which doesn't seem to violate the ABI rules you quoted.

That's good to know I guess, although I'm not sure what it
tells me.  My impression is that using attribute__((packed))
produces code that may be less portable than not using it.
Generally I try to write code that avoids compiler-specific
constructs whenever feasible.

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


#401233 — Re: Storage needed when there are bit-field members

Fromscott@slp53.sl.home (Scott Lurndal)
Date2026-08-16 15:20 +0000
SubjectRe: Storage needed when there are bit-field members
Message-ID<jzkgS.4883$4QJ.2251@fx21.iad>
In reply to#401223
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>scott@slp53.sl.home (Scott Lurndal) writes:
>
>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>>
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>>
>>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>>>
>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>>>>>
>>>>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

>>>> Here's a test program:
>>>>
>>>> #include <stdio.h>
>>>> #include <stddef.h>
>>>> int main(void) {
>>>>     struct s1 { unsigned char bf:1;      unsigned char c; };
>>>>     struct s2 { unsigned short bf:1;     unsigned char c; };
>>>>     struct s3 { unsigned int bf:1;       unsigned char c; };
>>>>     struct s4 { unsigned long bf:1;      unsigned char c; };
>>>>     struct s5 { unsigned long long bf:1; unsigned char c; };
>>
>> FWIW, adding GCC's  __attribute__((packed)) to each of those, we see:
>>
>>> type               size offset struct-size
>>> unsigned char      1    1      2
>>> unsigned short     2    1      2
>>> unsigned int       4    1      4
>>> unsigned long      8    1      8
>>> unsigned long long 8    1      8
>>
>> type               size offset struct-size
>> unsigned char      1    1      2
>> unsigned short     2    1      2
>> unsigned int       4    1      2
>> unsigned long      8    1      2
>> unsigned long long 8    1      2
>>
>> Which doesn't seem to violate the ABI rules you quoted.
>
>That's good to know I guess, although I'm not sure what it
>tells me.  My impression is that using attribute__((packed))
>produces code that may be less portable than not using it.
>Generally I try to write code that avoids compiler-specific
>constructs whenever feasible.

I generally only use the packed attribute when creating
a C struct to match a hardware register, data structure or
data packet.

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


#401331 — Re: Storage needed when there are bit-field members

Fromantispam@fricas.org (Waldek Hebisch)
Date2026-08-19 19:34 +0000
SubjectRe: Storage needed when there are bit-field members
Message-ID<11650g9$19gjl$1@paganini.bofh.team>
In reply to#400280
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
> [...]
<snip>
> One possible approach would be to use the declared type only to
> determine the signedness of the bit-field (and its conversion
> behavior in the case of bool), and the upper bound for the number
> of bits (`int bf:33` is a constraint violation if int is 32 bits).
> In this relatively simple approach, there's no point in defining
> a bit-field with one of the char or short types.
> 
> Using gcc on Linux, if I define a 1-bit bit-field with a 64-bit type,
> that forces the containing structure to be at least 64 bits -- but
> not by reserving a 64-bit region to hold the bit-field.  If I define
> a struct containing a 1-bit unsigned long long bit-field followed by
> a 1-byte ordinary member, the second member is at a 1-bytes offset.
> 
> I had gotten the impression that the behavior is imposed by ABIs,
> but my copy of the "System V Application Binary Interface AMD64
> Architecture Processor Supplement" just says:
> 
>     - bit-fields are allocated from right to left
>     - bit-fields must be contained in a storage unit appropriate for
>       its declared type
>     - bit-fields may share a storage unit with other struct / union
>       members
> 
> which doesn't seem to be enough to specify the behavior I see
> (and I find it annoyingly vague).
> 
> Is there a document (ABI, compiler document, whatever) that specifies
> the (odd, to me) behavior I'm seeing?
> 
> Here's a test program:
<snip>
> and its output on my system (Ubuntu, x86_64):
> 
> type               size offset struct-size
> unsigned char      1    1      2
> unsigned short     2    1      2
> unsigned int       4    1      4
> unsigned long      8    1      8
> unsigned long long 8    1      8
> 
> Again, the declared type of a bit-field doesn't affect how the
> bit-field itself is allocated, but it does affect the size of the
> containing struct, but it doesn't prevent other members from being
> allocated within that space.

I leave it to language and standard lawyers to discuss if such
behaviour is mandated, but I find results of the test program
obvious given how gcc behaves is general.  First, IIUC given
bit field should be at fixed bit offset within its storage unit.
Second, storage units are allocated at byte addresses with
appropriate alignment.  Third, the passage above says that
storage unit must be approptiate for its type, so 1 byte in
case of unsigned char, 2 bytes in case of unsigend short,
4 bytes in case of unsigned int, 8 bytes in case of unsignend
long.  Together, size of storage unit, its alignment and
fixed bit offset of bit field within storage unit determines
mininal size of structure needed to hold the bitfield.
When this size is bigger then 1, then there is enough space
within the storage unit to place the extra character there.
When type is unsigned char, then size is 1 and there are
no space to have bit field and char withing a single storage
unit, so second one is allocated giving total size of the
struct as 2.  So in each case we get the struct size above.

Other post mentioned gcc "packed".  gcc "packed" does not
respect alignment rules, so in such cases 2 byte are enough
regardless of type.

-- 
                              Waldek Hebisch

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


#401341 — Re: Storage needed when there are bit-field members

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-08-19 15:26 -0700
SubjectRe: Storage needed when there are bit-field members
Message-ID<1165ai6$314h2$2@kst.eternal-september.org>
In reply to#401331
antispam@fricas.org (Waldek Hebisch) writes:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
[...]
>> I had gotten the impression that the behavior is imposed by ABIs,
>> but my copy of the "System V Application Binary Interface AMD64
>> Architecture Processor Supplement" just says:
>> 
>>     - bit-fields are allocated from right to left
>>     - bit-fields must be contained in a storage unit appropriate for
>>       its declared type
>>     - bit-fields may share a storage unit with other struct / union
>>       members
>> 
>> which doesn't seem to be enough to specify the behavior I see
>> (and I find it annoyingly vague).
>> 
>> Is there a document (ABI, compiler document, whatever) that specifies
>> the (odd, to me) behavior I'm seeing?

[...]

> I leave it to language and standard lawyers to discuss if such
> behaviour is mandated, but I find results of the test program
> obvious given how gcc behaves is general.  First, IIUC given
> bit field should be at fixed bit offset within its storage unit.
> Second, storage units are allocated at byte addresses with
> appropriate alignment.  Third, the passage above says that
> storage unit must be approptiate for its type, so 1 byte in
> case of unsigned char, 2 bytes in case of unsigend short,
> 4 bytes in case of unsigned int, 8 bytes in case of unsignend
> long.

Thank you, that's the point I had overlooked (even though I
quoted it).

The ABI document's statement that "bit-fields must be contained in
a storage unit appropriate for its declared type", can reasonably
be read to mean that an unsigned char bit-field is contained in a
1-byte storage unit, and an unsigned long long bit-field is contained
in an 8-byte storage unit (given that unsigned long long is 8 bytes).

I still find the language vague (and ungrammatical).  What exactly
does "appropriate" mean?  Could an implementation decide that a
32-bit storage unit is "appropriate" for an unsigned short bit-field?
Presumably not, since that would break binary compatibility, but
I don't see that it would violate the wording of the ABI.

The C standard's language is also vague, but it's not trying to
require binary compatibility.

    An implementation may allocate any addressable storage unit
    large enough to hold a bit-field. If enough space remains,
    a bit-field that immediately follows another bit-field in a
    structure shall be packed into adjacent bits of the same unit.

[...]

> Other post mentioned gcc "packed".  gcc "packed" does not
> respect alignment rules, so in such cases 2 byte are enough
> regardless of type.

gcc "packed" can also cause quiet crashes on some systems.  It can
result in, for example, an int member being allocated at an odd address.
Passing the address of such a member to a function that assumes the
pointed-to object is correctly aligned can result in Bad Things
Happening.  (On x86, as I understand it, misaligned accesses
are merely somewhat slower than aligned accesses.)

<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51628>
<https://stackoverflow.com/q/8568432/827263>
<https://stackoverflow.com/a/8568441/827263>

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

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


#401347 — Re: Storage needed when there are bit-field members

FromDavid Brown <david.brown@hesbynett.no>
Date2026-08-20 11:00 +0200
SubjectRe: Storage needed when there are bit-field members
Message-ID<1166fo6$3blln$1@dont-email.me>
In reply to#401341
On 20/08/2026 00:26, Keith Thompson wrote:
> antispam@fricas.org (Waldek Hebisch) writes:
>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
[...]
>> Other post mentioned gcc "packed".  gcc "packed" does not
>> respect alignment rules, so in such cases 2 byte are enough
>> regardless of type.
> 
> gcc "packed" can also cause quiet crashes on some systems.  It can
> result in, for example, an int member being allocated at an odd address.
> Passing the address of such a member to a function that assumes the
> pointed-to object is correctly aligned can result in Bad Things
> Happening.  (On x86, as I understand it, misaligned accesses
> are merely somewhat slower than aligned accesses.)
> 
> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51628>
> <https://stackoverflow.com/q/8568432/827263>
> <https://stackoverflow.com/a/8568441/827263>
> 


gcc "packed" can cause problems only if you don't use the compiler 
correctly (or if there are bugs in the compiler, as happens 
occasionally.  gcc's bugzilla seems to be having trouble, so I have not 
checked your bug link).

As you say, "packed" means that struct fields can be misaligned.  This 
has two potential problems.

One is that if you take the address of a field, you then have a pointer 
whose value is invalid for dereferencing as that type - so dereferencing 
it is UB.  (You can still convert it to a character pointer and 
dereference that.)  A compiler could therefore assume that if you have 
"int * p;" and you dereference it, then "p" must be correctly aligned. 
AFAIUI gcc does not make such assumptions, precisely because misaligned 
pointers do turn up in some code (either from the use of "packed" or by 
other means), and it is not an optimisation that is likely to be useful 
in any but the most obscure niche cases.  (And if you have code in that 
category, you can always use __builtin_assume_aligned() to give the 
compiler the additional information.)

The real problem with misaligned data is that on some systems, accessing 
misaligned data is not supported by the hardware.  Such hardware 
certainly exists.  From the links you gave, it appears to apply to 
SPARCs.  It certainly applies to some of the smaller and cheaper ARM 
Cortex-M cores (M0, M1, M23 - perhaps more).  And even on bigger 
devices, there can particular instructions that require correct 
alignment, such as "move multiple registers" or "load/store double 
register".  In the x86 world, I believe there are some SIMD load/store 
instructions that must use aligned addresses.  For most processors, and 
most instructions, misaligned accesses work but are a little slower than 
aligned accesses.

If a misaligned access is not supported, the effects vary by device. 
Some will trigger a hardware fault and a program crash.  Some will have 
a hardware fault and then software emulation of the misaligned access - 
then it will "work", but be /massively/ slower.  And for some you simply 
get the wrong access - your program silently does the wrong thing.  (On 
the msp430, trying to access a 16-bit value at an odd address had - in 
my brief testing long ago - the effect of accessing the data at one bye 
lower address but with swapped endianness.  This is not a documented 
effect, however, so not something to rely on.)

gcc is smart enough to use smaller accesses when it knows it is 
necessary.  Accessing a misaligned 32-bit field when targeting a 
Cortex-M4 will give normal load/store 32-bit instructions - when 
targeting an M23, it will generate multiple 8-bit or 16-bit load/stores. 
  And if you take a pointer to a packed field, you get a warning.  So I 
think you have to put a bit of effort into getting in trouble here - you 
have to use pointers and ignore warnings, or use inappropriate 
command-line switches or generate code targeting one processor and try 
to run it on a different processor.

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


#401350 — Re: Storage needed when there are bit-field members

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-08-20 03:30 -0700
SubjectRe: Storage needed when there are bit-field members
Message-ID<1166l0m$3d0b0$1@kst.eternal-september.org>
In reply to#401347
David Brown <david.brown@hesbynett.no> writes:
> On 20/08/2026 00:26, Keith Thompson wrote:
>> antispam@fricas.org (Waldek Hebisch) writes:
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
> [...]
>>> Other post mentioned gcc "packed".  gcc "packed" does not
>>> respect alignment rules, so in such cases 2 byte are enough
>>> regardless of type.
>> gcc "packed" can also cause quiet crashes on some systems.  It can
>> result in, for example, an int member being allocated at an odd address.
>> Passing the address of such a member to a function that assumes the
>> pointed-to object is correctly aligned can result in Bad Things
>> Happening.  (On x86, as I understand it, misaligned accesses
>> are merely somewhat slower than aligned accesses.)
>> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51628>
>> <https://stackoverflow.com/q/8568432/827263>
>> <https://stackoverflow.com/a/8568441/827263>
>
> gcc "packed" can cause problems only if you don't use the compiler
> correctly (or if there are bugs in the compiler, as happens
> occasionally.  gcc's bugzilla seems to be having trouble, so I have
> not checked your bug link).

That may be the case now, but it was definitely causing runtime bus
errors on some systems when I reported it.  It was later marked as
FIXED.

> As you say, "packed" means that struct fields can be misaligned.  This
> has two potential problems.
>
> One is that if you take the address of a field, you then have a
> pointer whose value is invalid for dereferencing as that type - so
> dereferencing it is UB.  (You can still convert it to a character
> pointer and dereference that.)  A compiler could therefore assume that
> if you have "int * p;" and you dereference it, then "p" must be
> correctly aligned. AFAIUI gcc does not make such assumptions,
> precisely because misaligned pointers do turn up in some code (either
> from the use of "packed" or by other means), and it is not an
> optimisation that is likely to be useful in any but the most obscure
> niche cases.  (And if you have code in that category, you can always
> use __builtin_assume_aligned() to give the compiler the additional
> information.)

I'm not sure what assumptions gcc makes now.  Once you add something
outside the sco of the standard like `__attribute__((packed))`, the
behavior is arguably undefined anyway.  I can't reproduce the original
symptom with a modern gcc, but that may be because I don't have access
to a system that traps on unaligned accesses.

[...]

> gcc is smart enough to use smaller accesses when it knows it is
> necessary.  Accessing a misaligned 32-bit field when targeting a
> Cortex-M4 will give normal load/store 32-bit instructions - when
> targeting an M23, it will generate multiple 8-bit or 16-bit
> load/stores.   And if you take a pointer to a packed field, you get a
> warning.  So I think you have to put a bit of effort into getting in
> trouble here - you have to use pointers and ignore warnings, or use
> inappropriate command-line switches or generate code targeting one
> processor and try to run it on a different processor.

The problem is that if you have a separately compiled function like:

void inc(int *p) {
     (*p)++;
}

the compiler has no way to know whether smaller (and perhaps
significantly more expensive) accesses are necessary.  Direct access to
a packed member is easy enough, but once you take its address and pass
it somewhere, there's no good way to deal with it.

gcc added a warning option -Waddress-of-packed-member.

I haven't been able to get any code to run on SPARC via godbolt.org.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

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


#401355 — Re: Storage needed when there are bit-field members

FromDavid Brown <david.brown@hesbynett.no>
Date2026-08-20 13:58 +0200
SubjectRe: Storage needed when there are bit-field members
Message-ID<1166q5g$3dg4d$2@dont-email.me>
In reply to#401350
On 20/08/2026 12:30, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 20/08/2026 00:26, Keith Thompson wrote:
>>> antispam@fricas.org (Waldek Hebisch) writes:
>>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>> [...]
>>>> Other post mentioned gcc "packed".  gcc "packed" does not
>>>> respect alignment rules, so in such cases 2 byte are enough
>>>> regardless of type.
>>> gcc "packed" can also cause quiet crashes on some systems.  It can
>>> result in, for example, an int member being allocated at an odd address.
>>> Passing the address of such a member to a function that assumes the
>>> pointed-to object is correctly aligned can result in Bad Things
>>> Happening.  (On x86, as I understand it, misaligned accesses
>>> are merely somewhat slower than aligned accesses.)
>>> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51628>
>>> <https://stackoverflow.com/q/8568432/827263>
>>> <https://stackoverflow.com/a/8568441/827263>
>>
>> gcc "packed" can cause problems only if you don't use the compiler
>> correctly (or if there are bugs in the compiler, as happens
>> occasionally.  gcc's bugzilla seems to be having trouble, so I have
>> not checked your bug link).
> 
> That may be the case now, but it was definitely causing runtime bus
> errors on some systems when I reported it.  It was later marked as
> FIXED.
> 

As I say, I can't seem to get any response from the gcc bugzilla server, 
so I can't look at the link for now.  Certainly gcc has bugs, some of 
which can be serious.

>> As you say, "packed" means that struct fields can be misaligned.  This
>> has two potential problems.
>>
>> One is that if you take the address of a field, you then have a
>> pointer whose value is invalid for dereferencing as that type - so
>> dereferencing it is UB.  (You can still convert it to a character
>> pointer and dereference that.)  A compiler could therefore assume that
>> if you have "int * p;" and you dereference it, then "p" must be
>> correctly aligned. AFAIUI gcc does not make such assumptions,
>> precisely because misaligned pointers do turn up in some code (either
>> from the use of "packed" or by other means), and it is not an
>> optimisation that is likely to be useful in any but the most obscure
>> niche cases.  (And if you have code in that category, you can always
>> use __builtin_assume_aligned() to give the compiler the additional
>> information.)
> 
> I'm not sure what assumptions gcc makes now.  Once you add something
> outside the sco of the standard like `__attribute__((packed))`, the
> behavior is arguably undefined anyway.  I can't reproduce the original
> symptom with a modern gcc, but that may be because I don't have access
> to a system that traps on unaligned accesses.
> 

You can use godbolt to generate the code.  If you are targetting a 
processor that does not support misaligned accesses, it should generate 
smaller accesses for misaligned packed data.  With the following link, 
you can try changing the "-mcpu=cortex-23" to "cortex-m33" and see the 
difference in the code.

<https://godbolt.org/z/PqGabdfWG>

If you can make an example where a modern gcc for the target hardware 
generates multiple small accesses, and an older version generates a 
misaligned big access, then that would probably show the issue even 
without access to the hardware.

> [...]
> 
>> gcc is smart enough to use smaller accesses when it knows it is
>> necessary.  Accessing a misaligned 32-bit field when targeting a
>> Cortex-M4 will give normal load/store 32-bit instructions - when
>> targeting an M23, it will generate multiple 8-bit or 16-bit
>> load/stores.   And if you take a pointer to a packed field, you get a
>> warning.  So I think you have to put a bit of effort into getting in
>> trouble here - you have to use pointers and ignore warnings, or use
>> inappropriate command-line switches or generate code targeting one
>> processor and try to run it on a different processor.
> 
> The problem is that if you have a separately compiled function like:
> 
> void inc(int *p) {
>       (*p)++;
> }
> 
> the compiler has no way to know whether smaller (and perhaps
> significantly more expensive) accesses are necessary.  Direct access to
> a packed member is easy enough, but once you take its address and pass
> it somewhere, there's no good way to deal with it.

Yes.  The best it can do is warn you when you take the address of the 
packed field.

> 
> gcc added a warning option -Waddress-of-packed-member.

Exactly.  (It was added in gcc 9, as far as I can tell.)

> 
> I haven't been able to get any code to run on SPARC via godbolt.org.
> 

I could not see incorrect code generated for SPARC gcc, but I am not 
very familiar with SPARC assembly, my example code may not have shown 
the problem, and godbolt only has back to gcc 12 for the SPARC.  So my 
own tests are far from conclusive.

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


#401370 — Re: Storage needed when there are bit-field members

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-08-20 13:37 -0700
SubjectRe: Storage needed when there are bit-field members
Message-ID<1167oir$3ptto$2@kst.eternal-september.org>
In reply to#401355
David Brown <david.brown@hesbynett.no> writes:
[...]
> If you can make an example where a modern gcc for the target hardware
> generates multiple small accesses, and an older version generates a
> misaligned big access, then that would probably show the issue even
> without access to the hardware.

Yes, but I lack both the familiarity with the relevant assembly
languages and the patience to do that.

[...]

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

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


#401396 — Re: Storage needed when there are bit-field members

FromMichael S <already5chosen@yahoo.com>
Date2026-08-21 14:31 +0300
SubjectRe: Storage needed when there are bit-field members
Message-ID<20260821143125.000012cb@yahoo.com>
In reply to#401347
On Thu, 20 Aug 2026 11:00:54 +0200
David Brown <david.brown@hesbynett.no> wrote:

> It certainly applies to some of the smaller and
> cheaper ARM Cortex-M cores (M0, M1, M23 - perhaps more).

Are you sure about M1?
If true, it is disappointing.

I would not touch Cortex-M0 or M23 for many other reasons so can't
be disappointed about them.

OTOH, M1 is something that in theory I like.
Never used it, because original licensing terms were absolute
non-starter for sort of projects that we are specializing in (volumes
rarely reaching 1000 units and never 10,000), but I am very likely to
use it if we ever chose to work with Microsemi, on which licensing of
M1 is much saner.

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


#401397 — Re: Storage needed when there are bit-field members

FromDavid Brown <david.brown@hesbynett.no>
Date2026-08-21 13:41 +0200
SubjectRe: Storage needed when there are bit-field members
Message-ID<1169dgl$7usb$1@dont-email.me>
In reply to#401396
On 21/08/2026 13:31, Michael S wrote:
> On Thu, 20 Aug 2026 11:00:54 +0200
> David Brown <david.brown@hesbynett.no> wrote:
> 
>> It certainly applies to some of the smaller and
>> cheaper ARM Cortex-M cores (M0, M1, M23 - perhaps more).
> 
> Are you sure about M1?
> If true, it is disappointing.

I haven't dug through the documentation, but gcc certainly thinks so - 
packed fields are accessed by byte rather than misaligned word accesses. 
  It is possible, of course, that gcc is pessimistic here, or that 
misaligned accesses are an optional feature for the core.

Since the M1 targets soft cores on programmable logic, and support for 
misaligned accesses takes extra logic (consuming space and possibly 
reducing maximum clock speed) for a feature that is rarely useful on 
embedded systems, it does not surprise me that the M1 does not support it.

> 
> I would not touch Cortex-M0 or M23 for many other reasons so can't
> be disappointed about them.

I have not used these cores either, but there is nothing inherently 
wrong with them - they are useful for small, cheap and low-power 
microcontrollers.  I am sure there are aspects of these cores where I 
would have preferred a different choice of which features are missing 
(compared to their larger brother cores), but I expect that would always 
be true.

> 
> OTOH, M1 is something that in theory I like.
> Never used it, because original licensing terms were absolute
> non-starter for sort of projects that we are specializing in (volumes
> rarely reaching 1000 units and never 10,000), but I am very likely to
> use it if we ever chose to work with Microsemi, on which licensing of
> M1 is much saner.
> 

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


Page 1 of 3  [1] 2 3  Next page →

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


csiph-web