Memmove in place of effective type change (type-punning)

In the next question: What is the correct way to enter floating point numbers in int and vice versa? , the conclusion is that the way to create doubles from whole bits and vice versa memcpy.

This is good, and the conversion method pseudo_castfound is found:

template <typename T, typename U>
inline T pseudo_cast(const U &x)
{
    static_assert(sizeof(T) == sizeof(U));    
    T to;
    std::memcpy(&to, &x, sizeof(T));
    return to;
}

and I would use it as follows:

int main(){
  static_assert(std::numeric_limits<double>::is_iec559);
  static_assert(sizeof(double)==sizeof(std::uint64_t));
  std::uint64_t someMem = 4614253070214989087ULL;
  std::cout << pseudo_cast<double>(someMem) << std::endl; // 3.14
}

My interpretation of just reading the standard and cppreference is / was that it should also be possible to use memmoveto change the effective type in place, for example:

template <typename T, typename U>
inline T& pseudo_cast_inplace(U& x)
{
    static_assert(sizeof(T) == sizeof(U));
    T* toP = reinterpret_cast<T*>(&x);
    std::memmove(toP, &x, sizeof(T));
    return *toP;
}

template <typename T, typename U>
inline T pseudo_cast2(U& x)
{
    return pseudo_cast_inplace<T>(x); // return by value
}

- ( cv , 5 cppreference/reinterpret_cast). memcpy memmove (ยง6.9.2), T U .

? gcc clang. memmove , to cppreference std:: memmove memmove,

: , , dest.


: ( segfault), @hvd. ! , ?

+4
3

++ double . ( ), , . ++ 14, ++ 17 [intro.object]:

(6.1), (8.3.4) (12.3) (7.4, 15.2).

double , . , T to;. .

, new T , U, , &x memmove, , x, x new.

+3

, UB.

:

int main()
{
    long x = 10;
    something_with_x(x*10);
    double& y = pseudo_cast_inplace<double>(x);
    y = 20;
    something_with_y(y*10);
}

- , , as-if:

int main()
{
    long x = 10;
    double& y = pseudo_cast_inplace<double>(x);
    y = 20;
    something_with_x(x*10);   // uh-oh!
    something_with_y(y*10);
}

, :

template <typename T, typename U>
inline T pseudo_cast(U&& x)
{
    static_assert(sizeof(T) == sizeof(U));
    T result;
    std::memcpy(std::addressof(result), std::addressof(x), sizeof(T));
    return result;
}

(.. - , ) - , gcc -O2

+2

double, uint64_t - undefined, , double uint64_t intro.object:

- , , . a b , , , , , , ; .

0

Source: https://habr.com/ru/post/1687488/


All Articles