3

There's a lot of advice out there saying not to use bitfields but to do the bit arithmetic manually (e.g., When to use bit-fields in C?) because bitfield layouts are implementation-defined.

Is this practically a problem? I've noticed the SysV ABI for x86-64, for example, defines how bitfields should be laid out, so I suppose using bitfields on this platform shouldn't be problematic even if I mix object code generated by different compilers.

Are bitfields similarly standardized on other platforms too? (I'm mainly interested in Linux (SysV ABI), MacOs, and CygWin.)

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • 1
    Note that Linux on x86 and x86-64 follows the SysV ABIs. – Nate Eldredge May 04 '19 at 13:11
  • I've read that performance is worse using bitfields than masking. Makes sense because *nobody* uses them, so compiler makers won't bother optimizing that. I wonder if that's still true, though. – alx - recommends codidact May 04 '19 at 13:16
  • 1
    @CacahueteFrito `Makes sense because nobody uses them` very strong but nonsense opinion. Just take a look on the PIC or AVR XMEGA libraries – 0___________ May 04 '19 at 13:17
  • Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. https://stackoverflow.com/help/on-topic – Rob May 04 '19 at 13:18
  • 3
    Most o/s (platforms) have an ABI and the compilers on the platform will adhere to the ABI. However, if you’re transmitting binary data between different platforms, there’s no guarantee that bit-fields that can be handled on one platform can be interpreted sanely on the other. AFAIK, there’s no system call that uses bit-fields. – Jonathan Leffler May 04 '19 at 13:19
  • 2
    @Rob I don't think the question is _that_ opinion-based: Do (at least) the most popular platform standardize bit-fields where the C standard leaves things implementation defined? – Petr Skocik May 04 '19 at 13:21
  • @JonathanLeffler so they should not be used for it. But there are many interesting use cases – 0___________ May 04 '19 at 13:21
  • @P__J__ Note the italics. I guess compilers that have their libraries written using bitfields, such as XC8 (PIC), will produce the exact same code. But I wouldn't be surprised if GCC on x86_64 didn't optimize as much. However I wouldn't say PIC is a good example of optimization; it has the worst compiler I've ever used. – alx - recommends codidact May 04 '19 at 13:22
  • 2
    I take your word for it that there are interesting use cases. I’ve not seen them, but I don’t work interfacing to hardware registers etc. outside that work space, I think they have little interest. You’re generally better off using bit masks. – Jonathan Leffler May 04 '19 at 13:25
  • It is implementation-defined, but so what, as long as all the code uses the same implementation there is no issue. Very, very common of course. Only real corner-case is networking code. – Hans Passant May 04 '19 at 13:58

2 Answers2

1

As usually in the programming there is no one simple answer. It always depends on many circumstances.

IMO the the answer depends what you plan to use them for.

If you want to have specific bit size integers with predictable behavior and readable code - yes

struct 
{
    unsigned cnt: 3;
}three_bit_counter;

three_bit_counter.cnt++;

If you program uC - Yes

If you want to use the same code and "pack" data into the bitfield structures - no.

This are only some examples. When coding is good to consider many options and not be suggested by "gurus" opinions.

struct 
{
    unsigned cnt: 3;
    unsigned cnt1: 4;
}three_bit_counter;

unsigned cnt;


void inccnt(void)
{
    three_bit_counter.cnt++;

}
void inccnt1(void)
{
    three_bit_counter.cnt1++;

}

void inccntmask(void)
{
    unsigned tmp = cnt & 7;
    tmp++;
    tmp &= 7;

    cnt &= ~7;
    cnt |= tmp;

}

void inccnt1mask(void)
{
    unsigned tmp = cnt & (0b1111 << 3) >> 3;

    cnt &= ~(0b1111 << 3);
    tmp++;
    tmp &= 0b1111;
    cnt |= tmp << 3;

}
0___________
  • 60,014
  • 4
  • 34
  • 74
1

[...] bitfield layouts are implementation-defined.

Some aspects are implementation-defined. Others are unspecified, such as the size of the addressible storage unit reserved for a bitfield.

Is this practically a problem?

It depends on what you're trying to do. Many of the same issues that apply more broadly to structure types apply in microcosm to bitfields. Among them,

  • Like structures generally, structures containing bitfields will be interpreted consistently by any given implementation, but
  • Like structures generally, structures containing bitfields may be interpreted differently by different implementations -- possibly affecting only the bitfield members.
  • Like with structure member layout, implementations are afforded more freedom to choose bitfield layout than some programmers assume.

I've noticed the SysV ABI for x86-64, for example, defines how bitfields should be laid out, so I suppose using bitfields on this platform shouldn't be problematic even if I mix object code generated by different compilers.

Using bitfields does not present an interoperability problem when mixing code that can be relied upon to produce and use identical bitfield layouts.

Using bitfields does not present a portability problem for code that avoids depending on details of bitfield layout.

Those are conflicting concerns, because interoperability requires consistent layout, but relying on layout details creates a portability problem.

Are bitfields similarly standardized on other platforms too? (I'm mainly interested in Linux (SysV ABI), MacOs, and CygWin.)

Generally speaking, for hosted implementations (including all your examples) there will be a platform ABI defining bitfield layout, for software interoperability within a platform. ABI is not particularly relevant to standalone implementations, but many, if not all, such implementations do specify full details of bitfield layouts. If your concern is about whether you can link bitfield-using code compiled with different C implementations for the same platform and get a correctly-working program, then the answer is almost certainly "yes".

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Yes. The last sentence. Thanks. (The main reason I want to use bitfields is that in user-facing configuration structs (`struct ns_fn_cfg{unsigned flag1:1, flag2:1, flag3;}`) they're way nicer to use than requiring that the user OR some `NS_FN_CFG_FLAG1|NS_FN_CFG_FLAG2|NS_FN_CFG_FLAG3` and they also have better caller-side codegen than what I get with many`_Bool` fields that aren't bitfields.) – Petr Skocik May 04 '19 at 14:56