Strict C ++ 11 alias rules allow access to uint64_t via char *, char (&) [N], even std :: array <char, N> & with -fstrict-aliasing -Wstrict-aliasing = 2?

According to this stackoverflow answer about strict C ++ 11/14 alias rules :

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

  • dynamic type of object

  • cv-qualified version of the dynamic type of an object,

  • a type similar (as defined in 4.4) for the dynamic type of an object,
  • a type that is a signed or unsigned type corresponding to a dynamic type of an object,
  • a type that is a signed or unsigned type corresponding to the receipt version of the dynamic type of an object,
  • an aggregate or union type that includes one of the above types among its elements or non-static data elements (including a recursively element or non-static subaggregate or contains union data element),
  • a type that is (possibly cv-qualified) a base class type of a dynamic object type,
  • a or . char unsigned char

we can access another type of storage using

(1) char *

(2) char(&)[N]

(3) std::array<char, N> &

regardless of undefined behavior ?

constexpr uint64_t lil_endian = 0x65'6e'64'69'61'6e; 
    // a.k.a. Clockwise-Rotated Endian which allocates like
    // char[8] = { n,a,i,d,n,e,\0,\0 }

const auto& arr =   // std::array<char,8> &
    reinterpret_cast<const std::array<char,8> &> (lil_endian);

const auto& carr =  // char(&)[8]>
    reinterpret_cast<const char(&)[8]>           (lil_endian);

const auto* p =     // char *
    reinterpret_cast<const char *>(std::addressof(lil_endian));

int main()
{
    const auto str1  = std::string(arr.crbegin()+2, arr.crend() );

    const auto str2  = std::string(std::crbegin(carr)+2, std::crend(carr) );

    const auto sv3r  = std::string_view(p, 8);
    const auto str3  = std::string(sv3r.crbegin()+2, sv3r.crend() );

    auto lam = [](const auto& str) {
        std::cout << str << '\n'
                  << str.size() << '\n' << '\n' << std::hex;
        for (const auto ch : str) {
            std::cout << ch << " : " << static_cast<uint32_t>(ch) << '\n';
        }
        std::cout << '\n' << '\n' << std::dec;
    };

    lam(str1);
    lam(str2);
    lam(str3);
}

all lambda calls make:

endian
6

e : 65
n : 6e
d : 64
i : 69
a : 61
n : 6e

godbolt.org/g/cdDTAM (enable -fstrict-aliasing -Wstrict-aliasing = 2)

wandbox.org/permlink/pGvPCzNJURGfEki7

+4
2

char(&)[N] std::array<char, N> undefined. . , char(&)[N] std::array<char, N> - , char.

char, , (. ).

, , std::memcpy, [basic.types]/2:

( ) - T, , T, ([intro.memory]), , char, unsigned char std​::​byte ([cstddef.syn]). , . [:

#define N sizeof(T)
char buf[N];
T obj;                          // obj initialized to its original value
std::memcpy(buf, &obj, N);      // between these two calls to std​::​memcpy, obj might be modified
std::memcpy(&obj, buf, N);      // at this point, each subobject of obj of scalar type holds its original value

- ]

+3

: , . (*)

, . unsigned char [basic.types]/4:

T N unsigned char , T, N sizeof(T). , T.

:

  • lam(str1) - UB (Undefined );
  • lam(str2) - UB ( );
  • lam(str3) UB , char unsigned char, , . ( , )

, p const unsigned char* . 2 , , .


(*) : ; unsigned char std::byte, .

+2

Source: https://habr.com/ru/post/1691165/


All Articles