You can certainly have a pointer to a struct member, so this isn't the reason why you can't have pointers to bitfields. The reason is that bits are not addressable, fullstop.
You can certainly have a pointer to a struct member, so this isn't the reason why you can't have pointers to bitfields. The reason is that bits are not addressable, fullstop.
The restriction in C can only be explained as a limitation of the language itself -- although probably motivated by the implementation complexity it would require, for a niche use case.
For example, there are machines (some DSPs) that individual octects are not efficiently addressable and usually a C byte in these machines is 16 or 32 bita.
https://www.ralfj.de/blog/2018/07/24/pointers-and-bytes.html
I also happen to very much enjoy this piece on how the C abstract machine has very little in common with modern architecture.
Even if the ISA only allows word- or dword-aligned loads from memory, the addresses still typically enumerate bytes, not words or dwords.
Based on a quick summary of the MCS-51 that I googled up, it looks like its memory addressing scheme still assigns addresses to bytes, and has special operations that allow you to further specify a bit offset within that memory address.
There are also instructions which use an addressing scheme which takes an 8-bit bit address, with the 0x00 - 0x7f corresponding to lower memory, and 0x80 - 0xff corresponding to 16 specific registers in the Special Function Register set.
Nowadays a byte is conventionally eight bits, especially for measures like "megabyte", but the term octet is often used to avoid ambiguity. Commonly they're used for pointers, yet often only words are addressable by machine instructions (e.g. many ARM instructions take a byte address yet raise a hardware exception on use of unaligned addresses).
"byte: addressable unit of data storage large enough to hold any member of the basic character set of the execution environment"
Hence why the type that corresponds to it is "char"! Beyond that, the only thing that kinda sorta implies that it's the smallest addressable unit is the definition of CHAR_BIT:
"number of bits for smallest object that is not a bit-field (byte)"
This might be why the code space alphabet is defined by the standard so it will at least put an emphasis on 8 bits == 1 byte.
The question, though, was about whether it's the minimum addressable unit of memory. In the C memory model, it is, but by implication - you can't have two pointers that compare non-equal, but differ by less than 1, so a type with sizeof==1 is by definition the smallest you can uniquely address. However, the C memory model doesn't have to reflect the underlying hardware architecture.
The CPU itself used 32-bit addresses to access machine words, the size of which was determined by what was being accessed. External memory was limited to 32-bit. Internal memory had regions that could be 32-bit, 40-bit, or 48-bit. An address increment of 1 would thus move by that many bits.
Mercury Computer Systems shipped a byte-oriented port of gcc. Pointers to char and short were rotated and XORed as needed to reduce incompatibility. Pointers to larger objects were in the hardware format. This allowed a high degree of compatibility with ordinary software while still running efficiently when working with the larger objects. There was also a 64-bit double, unlike the 32-bit one in the other compiler. Data structures were all compatible with PowerPC and i860, allowing heterogeneous shared memory multiprocessor systems.
$ grep -rE ':[[:digit:]][[:digit:]]*;' /usr/include/ | wc -l
702
$ uname -a
OpenBSD orville.25thandClement.com 6.6 GENERIC.MP#3 amd64
$ grep -rE ':[[:digit:]][[:digit:]]*;' /usr/include/ | wc -l
276
$ uname -a
Linux alpine-3-10 4.9.65-1-hardened #2-Alpine SMP Mon Nov 27 15:36:10 GMT 2017 x86_64 Linux
$ grep -rE ':[[:digit:]][[:digit:]]*;' /usr/include/ | wc -l
532
$ uname -a
Linux splunk0 5.0.0-36-generic #39-Ubuntu SMP Tue Nov 12 09:46:06 UTC 2019 x86_64 x86_64 x86_64 GNU/LinuxIn fact, many internal coding standards forbid its use because it is poorly defined and compiler-dependent.
Moreover, it does not guarantee atomicity so if atomicity is critical then you want to access the actual bitfield 'manually'.
They are indeed trouble for super-portable interfaces. They also tempt some people into trouble with hardware drivers, but then that would already be trouble anyway due to instruction reordering in CPU or memory operation reordering beyond the CPU. (volatile is neither sufficient nor necessary)
In a normal emulator, none of that is a problem. Reasonable uses of bitfields are compatible between the x86_64 ELF ABI (Linux, etc.) and the Windows ABI. What you gain is C code that is simultaneously concise and readable.
For example, a CPU instruction can be represented in a header file by a union of anonymous structs, each of which contains a padding bitfield and a bitfield for part of the instruction. Access in the C file is then just as easy as for normal struct members. It works for non-CPU hardware too, like DMA descriptors and motherboard registers.
As I said, C's bit fields are often banned in coding guidelines.
ethdev->phy.foo = val; // foo is a bitfield in struct phy
cpu->status.irqlevel = newlevel; // irqlevel is a bitfield in the CPU's status word
No, I don't want a 2-argument macro (or worse, with an implied variable) called something like SET_FOO or SET_IRQLEVEL.
Crummy coding guidelines are not a useful argument against the value of bitfields in the C programming language. Coding guidelines can also ban floating-point types, recursion, or symbol names longer than 6 characters. The problem is not C. The problem is the coding guidelines.