What are the restrictions on modifying an object through a pointer to its byte representation in C++?

Viewed 114

I was confused by the following paragraph about type aliasing from cppreference (source):

Whenever an attempt is made to read or modify the stored value of an object of type DynamicType through a glvalue of type AliasedType, the behavior is undefined unless one of the following is true:

  • AliasedType and DynamicType are similar.
  • AliasedType is the (possibly cv-qualified) signed or unsigned variant of DynamicType.
  • AliasedType is std::byte, char, or unsigned char: this permits examination of the object representation of any object as an array of bytes.

Consider I have an object of a trivial type (such as a scalar) whose size is larger than 1 byte. In what ways (if at all), am I allowed to modify the byte representation of the object through a pointer to a different type without invoking undefined behaviour? For example:

int x = 5, y = 10;
std::byte* x_bytes = reinterpret_cast<std::byte*>(&x);

//#1: replacing the entire representation:
std::memcpy(x_bytes, &y, sizeof(int));

//#2: changing a random byte in the representation:
x_bytes[0] = (std::byte)3;

Are both of these operations allowed, or only #1?
The problem is that I don't know how to interpret the paragraph I quoted. The three bullets are exceptions to the rule that "Whenever an attempt is made to read or modify the stored value [...] the behavior is undefined", which would imply that both reading and writing are allowed if one of the bullets is applicable. However, the third bullet only mentions the "examination of the object representation", which implies read-only access.
I tried to find an appropriate standard page describing this problem in more detail, but I haven't been able to, so this was all I had that was relevant to the problem.

1 Answers

Are both of these operations allowed

Yes. There is no rule saying that you must modify all or nothing. Modifying a single byte is allowed.


However, the third bullet only mentions the "examination of the object representation", which implies read-only access.

The standard rule doesn't use such wording. This is the rule from the latest draft:

[basic.lval]

If a program attempts to access the stored value of an object through a glvalue whose type is not similar to one of the following types the behavior is undefined:

  • the dynamic type of the object,
  • a type that is the signed or unsigned type corresponding to the dynamic type of the object, or
  • a char, unsigned char, or std​::​byte type.

Access is defined as:

[defns.access]

⟨execution-time action⟩ read or modify the value of an object


Of course, modifying bytes by their index-order is quite dubious from portability perspective, since different systems store their bytes in different orders, and thus you would be modifying a byte with different order of significance on different systems.

Different behaviour on different systems is often undesirable.

Related