C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Fixing std::bit_cast padding bit issues

From: Jan Schultke <janschultke_at_[hidden]>
Date: Fri, 16 Jan 2026 15:20:11 +0100
>
> > I think some kind of "pad to zero" concept could have uses beyond
> this
> > case, and be useful in its own right. You could have :
> >
> > T padded_to_zero(const T& x)
> >
> > that would return a copy of x, where the all padding bits and bytes
> are
> > set to zero. And you could have :
> >
> > pad_to_zero(T& x)
> >
> > that would zero out the padding on an existing object.
> >
> >
> > That does not make any sense in the C++ object model. Padding bits are
> > bits that are not in the value representation, and they don't get
> > copied/preserved when values are copied.
>
> They are not copied or preserved with most copies, but they /are/
> accessible via things like memcpy and access using character or
> std::byte pointers. So sometimes they are relevant despite not being
> part of the value of the object.
>

You can copy them with memcpy (only at run-time), but examining the value
results in undefined behavior.


>
> > If you store the result of
> > padded_to_zero in a variable and copy that variable into a second one,
> > the padding bits of these variables may differ.
>
> Yes - /if/ you copy the object as a value, rather than the underlying
> representation.
>
> Suppose we have a structure with padding :
>
> struct S { uint8_t a; uint32_t c; };
>
> Assuming common alignments (and ignoring any other implementation
> dependent details for simplicity), there be 3 bytes of padding between
> "a" and "c" - somewhat akin to a hidden field "unsigned char b[3];".
>
> If you create an object S s1, then it's "b" field is unspecified. If
> you write "S s2 = s1;", then s2's "b" field is also unspecified, and you
> have no reason to suppose that s2.b and s1.b would be equal (even if it
> made sense to compare them). "memcmp(&s1, &s2, sizeof(S))" is not
> guaranteed to give 0.
>
> However, if you write "memcpy(&s2, &s1, sizeof(S));", then I think it is
> reasonable to expect "memcmp(&s1, &s2, sizeof(S))" to give 0 - even
> though the padding bytes are still unspecified - because you have copied
> a block of bytes, not values of type S.
>
> Am I correct to expect this? Or do all guarantees or information about
> the padding bytes "disappear" as soon as the memcpy() is complete?
>

You are expecting it because it "works in practice", but it's still
undefined behavior. memcpy nowadays is a compiler intrinsic, and small
copies like of eight bytes may be internally represented as just passing an
i64 around, which does god knows what with padding bits when that i64 lives
in a register.

It's also reasonable to expect the compiler to spot a branch based on
indeterminate bits within memcmp and optimize your code away entirely. It's
also reasonable to expect UBSan to terminate your program when you memcmp a
padded type, or for the compiler to treat such a call as equivalent to
std::unreachable() and not even emit IR for it.

When I write structs myself that would normally contain padding, and
> where I want to have consistency (because transferring structs into and
> out of code, hashes, and data serialisation is not uncommon), I add
> explicit "padding" or "dummy" fields so that I know everything is
> well-defined. But it would be much more convenient to be able to do
> this kind of thing in a more automated manner. But if there is no way
> to make sense of this within the C++ object model, so be it.
>

I can see how such a thing would be useful, although that seems like a
separate problem to me. There is also the issue of fundamental types that
contain padding, like _BitItn or long double, and those would need to be
broken down into smaller types by any utility that splits your types into
padding and non-padding bits.

There is even the problem of types like _BitInt(3) where the padding
doesn't nicely bundle into whole bytes. It is unclear how those could be
handled by pad_to_zero, other than to bit-cast and zero the padding bits,
which is exactly what I'm proposing.

Received on 2026-01-16 14:20:26