Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need for an intermediate struct in a type punning example with `std::bit_cast`

I was reading this excellent material about the strict aliasing rule: https://stackoverflow.com/a/51228315/21691539 or https://gist.github.com/shafik/a956a17d00024b32b35634eeba1eb49e

But in the section about std::bit_cast and an alleged limitation of std::bit_cast, I don't understand the need for both a std::memcpy and a std::bit_cast.

The provided example seemed a bit contrived and can be simplified to:

#include <bit>
#include <cstring>

struct some_chars {
    unsigned char arr[sizeof(unsigned int)] = {};
};
unsigned int foo(unsigned char *p) {
    some_chars a;
    std::memcpy(a.arr, p, sizeof(unsigned int));
    unsigned int result = std::bit_cast<unsigned int>(a);
    return result;
}

(see here)
(Here and in the following, p is assumed to point to a storage of at least sizeof(unsigned int) unsigned char)

I'm finding the purpose of the intermediate struct unclear. What would be wrong with the following?

unsigned int foo(unsigned char *p) {
    unsigned int result;
    std::memcpy(&result, p, sizeof(unsigned int));
    return result;
}

why not std::memcpy directly into an unsigned int as illustrated in cpprefence?

// reinterpreting
double d = 0.1;
//  std::int64_t n = *reinterpret_cast<std::int64_t*>(&d); // aliasing violation
std::int64_t n;
std::memcpy(&n, &d, sizeof d); // OK

LIVE

like image 318
Oersted Avatar asked Dec 09 '25 16:12

Oersted


1 Answers

bit_cast is for converting the object representation of one type to another type. But bit_cast requires having a live object of the source type. And the source type must be a value type.

p is a pointer to some bytes. And while p itself is a value type, which it points to isn't. bit_cast needs a value type, so you have to copy the desired bytes into a value type and then perform the cast.

What would be wrong with the following?

memcpying into a live object is only permitted to work by the standard if the source bits came from a live object of that type, as described in [basic.types]/2&3. So if p pointed to data that is an object representation of an unsigned int created by a copy from a valid unsigned int, then it does work. But if p pointed to, say, various bits you loaded from a file or got from the internet or wherever, then as far as the standard is concerned, all bets are off.

bit_cast is less restrictive; as long as the bits represent a valid value of the new type, bit_cast will manifest that value in the returned object type.

like image 171
Nicol Bolas Avatar answered Dec 12 '25 07:12

Nicol Bolas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!