ARTICLE AD BOX
This question is a follow-up of std::bit_cast padding and undefined behavior. This "revival" is motivated by my answer to Accessing object storage where I proposed a function to modify a given byte of an object, trying to avoid undefined behavior:
#include <bit> #include <cstddef> #include <cstdint> #include <type_traits> template <typename T> concept trivially_copyable = std::is_trivially_copyable_v<T>; namespace details { // required to pass a plain array to and from bit_cast template <typename T, std::size_t N> struct wrap_array { T arr[N]; }; } // namespace details template <trivially_copyable T> constexpr void set_byte(T& obj, std::size_t pos, std::byte val) { details::wrap_array<std::byte, sizeof(T)> obj_rep; // static only with c++>=23 // static details::wrap_array<std::byte,sizeof(T)> obj_rep; obj_rep = std::bit_cast<details::wrap_array<std::byte, sizeof(T)>, T>(obj); if (pos >= sizeof(T)) { return; } obj_rep.arr[pos] = val; obj = std::bit_cast<T, details::wrap_array<std::byte, sizeof(T)>>(obj_rep); }Looking at this I remembered the first linked question, to which I had no definitive answer.
I am wondering if this snippet is defined for structures with padding such as the one proposed in this question (the question would be the same for a structure with bit fields):
#include <cstdint> struct S40 { std::uint8_t a = 0x51; std::uint32_t b = 0xa353c0f1; };I digged deeper in the standard.
According to latest version of std::bit_cast:
If u is of unsigned ordinary character type or std::byte type, u has an indeterminate value if any of the bits in its value representation are indeterminate, or otherwise has an erroneous value.
So the first std::bit_cast above produces some std::bytes with indeterminate values.
Does it fall under the exceptions in basic.indet, leaving the program in a defined test and allowing to read this value, even though it is indeterminate?
Going one step further, if I change a byte containing an indeterminate value (giving it, now, a determinate one) and perform the second std::bit_cast, https://eel.is/c++draft/bit.cast#4 gives that padding bit of the returned struct are "unspecified" but I can't find a definition of this concept in this context (maybe unspecified behavior, that would say that the program is well-formed but the exact result depends on the actual implementation).
Is the resulting struct valid while the value representation correspond to a valid one for the type? Without undefined behavior?
My goal is to be sure that the function is valid when I want to change only bytes taking part in the value representation (but that may contain indeterminate bits, in the case of bit field). If I try to change padding bytes/bits, I am expecting that the object value remains unchanged and the program well-behaved.
