【问题标题】:Convert pointer to float?将指针转换为浮点数?
【发布时间】:2012-09-06 00:28:31
【问题描述】:

我有一个unsigned char*。通常这指向一块数据,但在某些情况下,指针是数据,即。将 int 值转换为 unsigned char* 指针 (unsigned char* intData = (unsigned char*)myInteger;),反之亦然。

但是,我需要使用 float 值执行此操作,并且它不断给我转换错误。

unsigned char* data;
float myFloat = (float)data;

我该怎么做?

【问题讨论】:

  • 你不能,至少不容易。如果没有一些神奇的技巧,这将永远不会包含有效信息,除非输入是正确的 IEEE 格式。
  • @RichardJ.RossIII 除非你知道一些我不知道的鬼鬼祟祟的东西(考虑到这是 C++,这不太可能)你可以很容易地做到这一点。
  • 您的平台上的sizeof(unsigned char *) 是否等于sizeof(float)?如果没有,您希望这会做什么,究竟是什么? (不要介意一般行为的可怕不确定性......)

标签: c++ type-conversion


【解决方案1】:

如果您的编译器支持它(GCC 支持),则使用联合。根据 C++ 标准,这是未定义的行为。

union {
    unsigned char* p;
    float f;
} pun;

pun.p = data;
float myFloat = pun.f;

如果sizeof(unsigned char *) == sizeof(float) 有效。如果指针大于浮点数,那么您必须重新考虑您的策略。

请参阅type punning 上的维基百科文章,尤其是use of a union 上的部分。

GCC 允许使用联合进行类型双关,只要您直接使用联合而不是类型转换为联合...see this IBM discussion on type-pun problems 了解使用 GCC 进行类型双关的正确和不正确方式。

另请参阅strong and weak typing 上的维基百科文章和type punning and strict aliasing 上经过深入研究的文章。

【讨论】:

  • 联合体的使用并不少见,但是在 C++ 中,这会导致两个方面的未定义行为:首先,它访问联合体的非活动成员(即,它访问的成员不是是最后一组)。其次,如果它按预期工作,那么它违反了严格的别名,通过不相关类型 (float) 的 glvalue 访问一种类型 (unsigned char*) 的对象。
  • 严格别名不涉及使用指向根本不同类型的指针引用相同的内存位置吗?这不是这里发生的事情。请参阅此 SO 问题stackoverflow.com/questions/2906365/…
  • 严格的别名规则是“如果程序试图通过以下类型之一的 glvalue 访问对象的存储值,则行为未定义:”(3.10p10)此代码是通过float 类型的glvalue 访问unsigned char * 对象的存储值。严格别名规则列出的任何类型都不涵盖这种情况。
  • 我看你是对的,所以虽然它可能很常见并且编译器可能支持它,但它是未定义的行为。
  • @bames53:感谢您的 cmets,我已编辑我的答案以包含您的意见。
【解决方案2】:

bit_cast:

template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
    static_assert(sizeof(Dest)==sizeof(Source), "size of destination and source objects must be equal");
    static_assert(std::is_trivially_copyable<Dest>::value, "destination type must be trivially copyable.");
    static_assert(std::is_trivially_copyable<Source>::value, "source type must be trivially copyable");

    Dest dest;
    std::memcpy(&dest, &source, sizeof(dest));
    return dest;
}

用法:

char *c = nullptr;
float f = bit_cast<float>(c);
c = bit_cast<char *>(f);

【讨论】:

    【解决方案3】:

    使用给定变量存储其他数据的唯一正确方法是按字节复制数据:

    template <typename T>
    void store(unsigned char * & p, T const & val)
    {
        static_assert(sizeof(unsigned char *) >= sizeof(T));
    
        char const * q = reinterpret_cast<char const *>(&val);
        std::copy(q, q + sizeof(T), reinterpret_cast<char *>(&p));
    }
    

    用法:

    unsigned char * p;
    store(p, 1.5);
    store(p, 12UL);
    

    匹配检索函数:

    template <typename T>
    T load(unsigned char * const & p)
    {
        static_assert(sizeof(unsigned char *) >= sizeof(T));
    
        T val;
        char const * q = reinterpret_cast<char const *>(&p);
        std::copy(q, q + sizeof(T), reinterpret_cast<char *>(&val));
    
        return val;
    }
    

    用法:

    auto f = load<float>(p);
    

    【讨论】:

    • 我认为您的 load 声明已关闭。您没有指定返回值。
    • @RichardJ.RossIII:谢谢,已修复!
    【解决方案4】:
    unsigned char* data;
    float myFloat = *(float*)data;
    

    【讨论】:

    • 你没有忘记&amp;吗?如果float 数据在指针本身中,你应该写&amp;data
    • 这将是未定义的行为,即使编写正确。
    • 我敢打赌这不是 OP 真正想要的 - 他们只是不知道如何提出问题
    • @AdrianCornish:实际上他说得很清楚......“指针是数据,即。将 int 值转换为 unsigned char* 指针 [...] 我需要做这带有 float 值”。
    • 我投了反对票,因为这根本不能解决所描述的问题。当问题是如何像访问浮点数一样访问 pointer 时,这会像访问浮点数一样访问指向的数据。这是float f = *(float*)data;float f = *(float*)&amp;data; 之间的区别。此外,这些强制转换具有未定义的行为,不应使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多