【问题标题】:C++ memcpy from double array to float arrayC ++ memcpy从双数组到浮点数组
【发布时间】:2023-03-16 17:25:01
【问题描述】:

是否可以安全地将双精度数组 memcpy 到浮点数组?

【问题讨论】:

  • 取决于您所说的安全。

标签: c++ memcpy


【解决方案1】:

取决于你想要什么。这些值肯定不会被保留。如果需要,请使用std::copy

#include <algorithm>

int main()
{
    double a[] = {1.618, 3.1416, 2.7, 0.707, 1.0};
    float b[5];
    std::copy(a, a + 5, b);
}

【讨论】:

  • 这不起作用(对于我在 VS2017 上),因为编译器不允许通过 std::copy 从双精度到浮点的隐式精度损失。我不得不使用 std::transform 函数,使用 lamda。这也更清楚地表明实际上正在发生显式的精度损失。
  • @AzP 听起来您已经选择了编译器选项以使其拒绝有效代码。 (或者有编译器错误)
  • @M.M 好吧,隐含的精度损失有点危险-取决于您使用的内容-并且使用警告级别 4 将导致编译器警告。由于我使用“将警告视为错误”,因此无法编译。从这个意义上说,“有效代码”并不意味着“好代码”。
【解决方案2】:

问题在于无法保证编译器对double 的二进制表示是float 的等效表示。为了将memcpy 用于多字节类型,底层表示必须相同(相同的布局)。您可以安全地将float 复制到floatintintdoubledouble

当源类型与目标类型不匹配时,您注定未定义的行为,例如从long 复制到charfloatdoublememcpy 函数不进行任何转换或执行任何促销。它只是复制。

【讨论】:

    【解决方案3】:

    就像许多其他人回答的那样,使用memcpy 不起作用,因为这两种类型(通常)大小不同。请在http://en.cppreference.com/w/cpp/language/types 上查看更多信息,或者更具体地说:

    浮点类型

    float - 单精度浮点类型。 通常为 IEEE-754 32 位浮点型

    double - 双精度浮点类型。通常为 IEEE-754 64 位浮点型

    long double - 扩展精度浮点类型。不一定映射到 IEEE-754 规定的类型。通常在 x86 和 x86-64 架构上使用 80 位 x87 浮点类型。

    使用 std::copy 会给你一个编译器警告(至少对我来说是 VS2015/VS2017 编译器),因为编译器不允许通过 std::copy 从 double 到 float 隐式损失精度,而不警告开发人员关于它。如果你设置了treat warnings as errors 标志,你会得到一个编译器错误。

    1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2316): error C2220: warning treated as error - no 'object' file generated
    1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2335): note: see reference to function template instantiation '_OutIt std::_Copy_unchecked1<_InIt,_OutIt>(_InIt,_InIt,_OutIt,std::_General_ptr_iterator_tag)' being compiled
    1>        with
    1>        [
    1>            _OutIt=float *,
    1>            _InIt=double *
    1>        ]
    1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2354): note: see reference to function template instantiation '_OutIt *std::_Copy_unchecked<_InIt,float*>(_InIt,_InIt,_OutIt)' being compiled
    1>        with
    1>        [
    1>            _OutIt=float *,
    1>            _InIt=double *
    1>        ]
    1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2364): note: see reference to function template instantiation '_OutIt std::_Copy_no_deprecate1<double*,_OutIt>(_InIt,_InIt,_OutIt,std::random_access_iterator_tag,std::random_access_iterator_tag)' being compiled
    1>        with
    1>        [
    1>            _OutIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>,
    1>            _InIt=double *
    1>        ]
    1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2373): note: see reference to function template instantiation '_OutIt std::_Copy_no_deprecate<_InIt,_OutIt>(_InIt,_InIt,_OutIt)' being compiled
    1>        with
    1>        [
    1>            _OutIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>,
    1>            _InIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>
    1>        ]
    1>test.cpp(153): note: see reference to function template instantiation '_OutIt std::copy<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>,std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>>(_InIt,_InIt,_OutIt)' being compiled
    1>        with
    1>        [
    1>            _OutIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>,
    1>            _InIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>
    1>        ]
    1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2316): warning C4244: '=': conversion from 'double' to 'float', possible loss of data
    

    相反,我建议使用 std::transform 函数,并结合执行特定演员阵容的 lamda。这也更清楚地表明实际上正在发生显式的精度损失。

    std::vector<double> doubles = { 5.0, 10.0, 242.130, 42.0 };
    std::vector<float> floats(doubles.size());
    std::transform(std::begin(doubles), std::end(doubles), std::begin(floats), [&](const double& value) { return static_cast<float>(value); });
    

    【讨论】:

    • 您的问题是这个“将警告视为错误”的荒谬选项。当然,transform 有效,更明确,因此在某些代码库中可能是首选,但 copy 的“无效”显然是错误的。
    • @MarcGlisse,真的,我会改变那个措辞。我不同意这个选项是“荒谬的”。
    【解决方案4】:

    一般情况下 - 不。

    在特定情况下,在给定平台上,floatdouble 的表示可能相同,并且复制会成功。但无论如何它没有任何实际意义。

    【讨论】:

      【解决方案5】:

      memcpy 与类型无关(只看到字节)并且不能进行类型转换。正如@AzP 所说,只需使用std::transform

      std::transform(a, a + 5, b, [](double d) -> float {return float(d);});
      

      【讨论】:

        猜你喜欢
        • 2021-03-04
        • 1970-01-01
        • 2014-12-09
        • 2018-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-22
        • 1970-01-01
        相关资源
        最近更新 更多