Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C.183 recommend bit_cast for type punning #1987

Open
mark0n opened this issue Oct 24, 2022 · 1 comment
Open

C.183 recommend bit_cast for type punning #1987

mark0n opened this issue Oct 24, 2022 · 1 comment
Assignees

Comments

@mark0n
Copy link

mark0n commented Oct 24, 2022

C.183 says that unions shouldn't be used for type punning but IMHO the guidance it provides on what to use instead leaves room for improvement. It mentions reinterpret_cast for casting to char*, unsigned char*, or std::byte. AFAIK we need to keep the following things in mind when punning types:

  1. reinterpret_cast<bar>(foo) is UB if bar has stricter alignment requirements than the type of foo.
  2. reinterpret_casting a pointer to a std::byte buffer to gadget* and then using this pointer to call member functions/access member variables is UB since no instance of gadget has been instantiated (object lifetime).
  3. In general reinterpret_cast might lead to UB due to aliasing (example demonstrating this).

I guess it would be better to suggest a way which is safe with respect to all three points. In particular I would like to suggest replacing the reinterpret_cast paragraph by something along the following lines:

Use std::bit_cast (introduced with C++20) for type punning. If your standard library doesn't support std::bit_cast, yet, use std::memcpy instead. This is preferred over using union or reinterpret_cast since bitcast and memcpy reliably prevent undefined behavior due to violated alignment/aliasing rules. In practice modern compilers are often able to eliminate the copy.

Example:
    // Assume sizeof(int) == sizeof(float) for these examples

    void if_you_must_pun(float& x)
    {
        auto i = std::bit_cast<int>(x);
        cout << i << '\n';
    }

    void if_you_must_pun_pre_cpp20(float& x)
    {
        int i;
        memcpy(&i, &x, sizeof(x));
        cout << i << '\n';
    }
@BjarneStroustrup
Copy link
Contributor

I think this should be left to a C++20 sweep of the whole CG.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants