Jens
Jens

Reputation: 9406

Does casting to an unrelated reference type violate the strict aliasing rule?

The strict aliasing rule says

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

— the dynamic type of the object,

— a cv-qualified version of the dynamic type of the object,

— a type similar (as defined in 4.4) to the dynamic type of the object,

— a type that is the signed or unsigned type corresponding to the dynamic type of the object,

— a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,

— an aggregate or union type that includes one of the aforementioned types among its elements or nonstatic data members (including, recursively, an element or non-static data member of a subaggregate or contained union)

I am wondering if the following program already contains undefined behavior and if there is "an access to the stored value":

#include <cstdint>

    void foo() {
        std::int32_t i = 1;
        float f = 1.0f;

        std::int32_t& r = reinterpret_cast<std::int32_t&>(f);

        std::int32_t* p = reinterpret_cast<std::int32_t*>(&f);
    }

From what I see, the cast of the float pointer to the int reference is equivalent to `*reinterpret_cast(&x):

A glvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast The result refers to the same object as the source glvalue, but with the specified type. [ Note: That is, for lvalues, a reference cast reinterpret_cast(x) has the same effect as the conversion *reinterpret_cast(&x) with the built-in & and * operators (and similarly for reinterpret_cast(x)). —end note ]

For pointers, reinterpret_cast boils down to conversion to void* and then to the target type:

An object pointer can be explicitly converted to an object pointer of a different type.72 When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast(static_cast(v)).

The semantics of the two static casts are defined as:

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T,” where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. The null pointer value is converted to the null pointer value of the destination type. If the original pointer value represents the address A of a byte in memory and A satisfies the alignment requirement of T, then the resulting pointer value represents the same address as the original pointer value, that is, A. The result of any other such pointer conversion is unspecified.

Since int32_t and float have same size and alignment, I should get a new pointer pointing to the same address. What I am wondering is if

a reference cast reinterpret_cast(x) has the same effect as the conversion *reinterpret_cast(&x) with the built-in & and * operators

already constitutes an access to the stored value or if that must be made somewhere later to violate the strict aliasing rule.

Upvotes: 3

Views: 183

Answers (1)

The casts you made are not an access to the objects i or f.

3.1 access [defns.access]

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

Since your program does not attempt to do the above, it does not violate strict aliasing. Trying to use those pointers/references to read or write will be a violation, however. So this is a fine line to tread. But merely obtaining the references/pointers is not against the first paragraph you stated. Casting to unrelated reference/pointer types only deals with an object's identity/address, and not its value.

Upvotes: 4

Related Questions