Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/numeric/bit cast"

From cppreference.com
< cpp‎ | numeric
(Since start_lifetime_as links to bit_cast, link back)
(Applied P2795R5 (Erroneous behaviour for uninitialized reads).)
 
Line 6: Line 6:
 
}}
 
}}
  
Obtain a value of type {{tt|To}} by reinterpreting the object representation of {{tt|From}}. Every bit in the value representation of the returned {{tt|To}} object is equal to the corresponding bit in the object representation of {{c|from}}. The values of padding bits in the returned {{tt|To}} object are unspecified.
+
Obtain a value of type {{tt|To}} by reinterpreting the object representation of {{tt|From}}. Every bit in the [[cpp/language/object#Object representation and value representation|value representation]] of the returned {{tt|To}} object is equal to the corresponding bit in the [[cpp/language/object#Object representation and value representation|object]] representation of {{c|from}}. The values of padding bits in the returned {{tt|To}} object are unspecified.
  
 
If there is no value of type {{tt|To}} corresponding to the value representation produced, the behavior is undefined. If there are multiple such values, which value is produced is unspecified.
 
If there is no value of type {{tt|To}} corresponding to the value representation produced, the behavior is undefined. If there are multiple such values, which value is produced is unspecified.
Line 12: Line 12:
 
A bit in the value representation of the result is ''indeterminate'' if it
 
A bit in the value representation of the result is ''indeterminate'' if it
 
* does not correspond to a bit in the value representation of {{tt|From}} (i.e. it corresponds to a padding bit), or
 
* does not correspond to a bit in the value representation of {{tt|From}} (i.e. it corresponds to a padding bit), or
* corresponds to a bit of an object that is not within its [[cpp/language/lifetime|lifetime]], or
+
* corresponds to a bit {{rev inl|until=c++26|of an object that}}{{rev inl|since=c++26|for which the smallest enclosing object}} is not within its {{lt|cpp/language/lifetime}}, or
* has an [[cpp/language/default initialization|indeterminate value]].
+
* has an [[cpp/language/default initialization#Indeterminate and erroneous values|indeterminate value]].
  
For each bit in the value representation of the result that is indeterminate, the smallest object containing that bit has an indeterminate value; the behavior is undefined unless that object is of {{c|unsigned char}} or {{lc|std::byte}} type. The result does not otherwise contain any indeterminate values.
+
{{rrev|since=c++26|
 +
A bit in the value representation of the result is ''erroneous'' if it corresponds to a bit for which the smallest enclosing object has an [[cpp/language/default initialization#Indeterminate and erroneous values|erroneous value]].
 +
}}
 +
 
 +
 
 +
{{rev begin}}
 +
{{rev|until=c++26|
 +
For each bit in the value representation of the result that is indeterminate, the smallest object containing that bit has an indeterminate value; the behavior is undefined unless that object is of an [[cpp/language/default initialization#Special cases|uninitialized-friendly type]].
 +
 
 +
The result does not otherwise contain any indeterminate values.
 +
}}
 +
{{rev|since=c++26|
 +
For each bit {{c|b}} in the value representation of the result that is indeterminate or erroneous, let {{c|u}} be the smallest object enclosing {{c|b}}:
 +
* If {{c|u}} is of [[cpp/language/default initialization#Special cases|uninitialized-friendly type]], {{c|u}} has an indeterminate value if any of the bits in its value representation are indeterminate, or otherwise has an erroneous value.
 +
* Otherwise, if {{c|b}} is indeterminate, the behavior is undefined.
 +
* Otherwise, the behavior is [[cpp/language/ub|erroneous]], and the result is as specified above.
 +
}}
 +
 
 +
The result does not otherwise contain any indeterminate or erroneous values.
 +
{{rev end}}
  
{{cpp/enable_if|{{c|1=sizeof(To) == sizeof(From)}} and both {{tt|To}} and {{tt|From}} are {{named req|TriviallyCopyable}} types}}.
+
{{cpp/enable if|{{c|1=sizeof(To) == sizeof(From)}} and both {{tt|To}} and {{tt|From}} are {{named req|TriviallyCopyable}} types}}.
  
This function template is {{tt|constexpr}} if and only if each of {{tt|To}}, {{tt|From}} and the types of all subobjects of {{tt|To}} and {{tt|From}}:
+
This function template is {{c/core|constexpr}} if and only if each of {{tt|To}}, {{tt|From}} and the types of all subobjects of {{tt|To}} and {{tt|From}}:
 
* is not a union type;
 
* is not a union type;
 
* is not a pointer type;
 
* is not a pointer type;
Line 26: Line 45:
 
* has no non-static data member of reference type.
 
* has no non-static data member of reference type.
  
=== Parameters ===
+
===Parameters===
 
{{par begin}}
 
{{par begin}}
 
{{par|from|the source of bits for the return value}}
 
{{par|from|the source of bits for the return value}}
 
{{par end}}
 
{{par end}}
  
=== Return value ===
+
===Return value===
 
An object of type {{tt|To}} whose value representation is as described above.
 
An object of type {{tt|To}} whose value representation is as described above.
  
=== Possible implementation ===
+
===Possible implementation===
To implement {{tt|std::bit_cast}}, ignoring the fact that it's [[cpp/language/constexpr|constexpr]], {{lc|std::memcpy}} can be used, when it is needed, to interpret the object representation as one of another type:
+
To implement {{tt|std::bit_cast}}, ignoring the fact that it's {{lt|cpp/language/constexpr}}, {{lc|std::memcpy}} can be used, when it is needed, to interpret the object representation as one of another type:
  
 
{{source|1=
 
{{source|1=
Line 50: Line 69:
 
         "This implementation additionally requires "
 
         "This implementation additionally requires "
 
         "destination type to be trivially constructible");
 
         "destination type to be trivially constructible");
 
+
   
 
     To dst;
 
     To dst;
 
     std::memcpy(&dst, &src, sizeof(To));
 
     std::memcpy(&dst, &src, sizeof(To));
Line 58: Line 77:
  
 
=== Notes ===
 
=== Notes ===
{{ltt|cpp/language/reinterpret_cast}} (or equivalent [[cpp/language/explicit_cast|explicit cast]]) between pointer or reference types shall not be used to reinterpret object representation in most cases because of the [[cpp/language/reinterpret_cast#Type aliasing|type aliasing rule]].
+
{{ltt|cpp/language/reinterpret_cast}} (or equivalent {{lt|cpp/language/explicit cast}}) between pointer or reference types shall not be used to reinterpret object representation in most cases because of the [[cpp/language/reinterpret_cast#Type aliasing|type aliasing rule]].
  
 
{{feature test macro|__cpp_lib_bit_cast|std=C++20|value=201806L|[[#Top|{{tt|std::bit_cast}}]]}}
 
{{feature test macro|__cpp_lib_bit_cast|std=C++20|value=201806L|[[#Top|{{tt|std::bit_cast}}]]}}
Line 92: Line 111:
 
===Defect reports===
 
===Defect reports===
 
{{dr list begin}}
 
{{dr list begin}}
{{dr list item|wg=cwg|dr=2482<!-- resolved by P1272R4 -->|std=C++20|before=it was unspecified whether UB would occur when involving indeterminate bits|after=specified}}
+
{{dr list item|wg=cwg|dr=2482|paper=P1272R4|std=C++20|before=it was unspecified whether UB would occur when involving indeterminate bits|after=specified}}
 
{{dr list end}}
 
{{dr list end}}
  

Latest revision as of 02:04, 23 April 2024

 
 
 
Defined in header <bit>
template< class To, class From >
constexpr To bit_cast( const From& from ) noexcept;
(since C++20)

Obtain a value of type To by reinterpreting the object representation of From. Every bit in the value representation of the returned To object is equal to the corresponding bit in the object representation of from. The values of padding bits in the returned To object are unspecified.

If there is no value of type To corresponding to the value representation produced, the behavior is undefined. If there are multiple such values, which value is produced is unspecified.

A bit in the value representation of the result is indeterminate if it

  • does not correspond to a bit in the value representation of From (i.e. it corresponds to a padding bit), or
  • corresponds to a bit of an object that(until C++26)for which the smallest enclosing object(since C++26) is not within its lifetime, or
  • has an indeterminate value.

A bit in the value representation of the result is erroneous if it corresponds to a bit for which the smallest enclosing object has an erroneous value.

(since C++26)


The result does not otherwise contain any indeterminate or erroneous values.

For each bit in the value representation of the result that is indeterminate, the smallest object containing that bit has an indeterminate value; the behavior is undefined unless that object is of an uninitialized-friendly type.

The result does not otherwise contain any indeterminate values.

(until C++26)

For each bit b in the value representation of the result that is indeterminate or erroneous, let u be the smallest object enclosing b:

  • If u is of uninitialized-friendly type, u has an indeterminate value if any of the bits in its value representation are indeterminate, or otherwise has an erroneous value.
  • Otherwise, if b is indeterminate, the behavior is undefined.
  • Otherwise, the behavior is erroneous, and the result is as specified above.
(since C++26)

This overload participates in overload resolution only if sizeof(To) == sizeof(From) and both To and From are TriviallyCopyable types.

This function template is constexpr if and only if each of To, From and the types of all subobjects of To and From:

  • is not a union type;
  • is not a pointer type;
  • is not a pointer to member type;
  • is not a volatile-qualified type; and
  • has no non-static data member of reference type.

Contents

[edit] Parameters

from - the source of bits for the return value

[edit] Return value

An object of type To whose value representation is as described above.

[edit] Possible implementation

To implement std::bit_cast, ignoring the fact that it's constexpr, std::memcpy can be used, when it is needed, to interpret the object representation as one of another type:

template<class To, class From>
std::enable_if_t<
    sizeof(To) == sizeof(From) &&
    std::is_trivially_copyable_v<From> &&
    std::is_trivially_copyable_v<To>,
    To>
// constexpr support needs compiler magic
bit_cast(const From& src) noexcept
{
    static_assert(std::is_trivially_constructible_v<To>,
        "This implementation additionally requires "
        "destination type to be trivially constructible");
 
    To dst;
    std::memcpy(&dst, &src, sizeof(To));
    return dst;
}

[edit] Notes

reinterpret_cast (or equivalent explicit cast) between pointer or reference types shall not be used to reinterpret object representation in most cases because of the type aliasing rule.

Feature-test macro Value Std Feature
__cpp_lib_bit_cast 201806L (C++20) std::bit_cast

[edit] Example

#include <bit>
#include <cstdint>
#include <iostream>
 
constexpr double f64v = 19880124.0; 
constexpr auto u64v = std::bit_cast<std::uint64_t>(f64v);
static_assert(std::bit_cast<double>(u64v) == f64v); // round-trip
 
constexpr std::uint64_t u64v2 = 0x3fe9000000000000ull;
constexpr auto f64v2 = std::bit_cast<double>(u64v2);
static_assert(std::bit_cast<std::uint64_t>(f64v2) == u64v2); // round-trip
 
int main()
{
    std::cout
        << "std::bit_cast<std::uint64_t>(" << std::fixed << f64v << ") == 0x"
        << std::hex << u64v << '\n'
        << "std::bit_cast<double>(0x" << std::hex << u64v2 << ") == "
        << std::fixed << f64v2 << '\n';
}

Possible output:

std::bit_cast<std::uint64_t>(19880124.000000) == 0x4172f58bc0000000
std::bit_cast<double>(0x3fe9000000000000) == 0.781250

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 2482
(P1272R4)
C++20 it was unspecified whether UB would occur when involving indeterminate bits specified

[edit] See also

implicitly creates objects in given storage with the object representation reused
(function template) [edit]