4

While there might be an XY issue that led me here, I am curious about the limits of the new bit_cast in C++20, and this seems a good illustration of it.

Note that there is nothing inherently wrong with std::memcpy and it does not cause undefined behavior. It is also enough of an idiom to generally be optimized out to be the equivalent of a cast. The problem I have is that the intent of its usage is not as clear as it could be and it seems more C than C++.

How could you use bit_cast to do the same thing (without any undefined behavior) as the following:

#include <cstring>

void ptr2array(short (&x)[], int offset, const void * ptr)
{
    std::memcpy(&(x[offset]), ptr, sizeof(void *));
}

void array2ptr(void * & ptr, int offset, short (&x)[])
{
    std::memcpy(ptr, &(x[offset]), sizeof(void *));
}

Note that the following is fundamentally a no-op (tested here: https://godbolt.org/z/ce9Ecx8TG)

void * tst(void * orig)
{
    short x[101];
    int offset = 67;
    void * ret=orig;

    ptr2array(x, offset, ret);
    array2ptr(ret, offset, x);

    return ret;
}

Keep in mind that memcpy works fine with the misalignment (using offset).

Also requiring an array of shorts, as opposed to char, avoids some of the leniencies with char, but keeps the alignment issues.

2
  • Look at possible implementation en.cppreference.com/w/cpp/numeric/bit_cast contains std::memcpy Commented Dec 17, 2021 at 16:59
  • @RichardCrittenyes, but I was looking for the opposite. The logistics of using bit_cast in this case are not easy to work out. Commented Dec 17, 2021 at 17:11

1 Answer 1

2

bit_cast is for doing conversions between objects. It creates a new object whose binary data comes from some other object. It doesn't work on language arrays because, while they are objects, they don't work like objects. You can't pass them around the same way you can other objects. They decay to pointers, you can't return arrays, etc.

You can bit_cast with std::array and similar types, but even those are potentially a problem. std::array<char, sizeof(void*)> for example is not required to have the size of a void*. And bit_cast only works if the source and destination objects have the same size.

bit_cast also returns the object it creates. Which means you cannot (easily) bit_cast into existing storage. Nor is it easy to do a bit_cast from a range of bytes.

If you're trying to copy bits of data into storage... just do that. bit_cast isn't here to replace every use of memcpy.

Sign up to request clarification or add additional context in comments.

4 Comments

When in doubt there's static_assert(sizeof(std::array<char, sizeof(void*)>) == sizeof(void*)); it ensures that the "potentially a problem" does not need to be paid attention at before it becomes actual problem.
@ÖöTiib: Well, you don't really need the static_assert; bit_cast is specifically constrained to require that the types have the same size. So you'll get a compile error either way.
Perhaps I misunderstood your explanation. With memcpy we theoretically need that static_assert (that I've not heard failing on any implementations).
@ÖöTiib: With memcpy, no such assert is needed. You can copy into the std::array::data() pointer which is guaranteed to be an array as big as you asked for. My point was about any hypothetical padding inserted after the array inside of the std::array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.