isocpp / isocpp/CppCoreGuidelines

C.183 recommend bit_cast for type punning

Open
#1,987 1 comment 1 reaction 1 assignee View on GitHub

@cubbimew is already working on this.

Since Jan 26, 2023.

Dominant language
CSS
Stars
45.3k
Forks
5.6k
PR merge metrics
No merged PRs in 30d

Description

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';
    }

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.