【问题标题】:Bitstream to Float Type Coercion比特流到浮点类型强制
【发布时间】:2010-02-18 19:22:44
【问题描述】:

我无法让以下代码正常工作。使用在线 IEEE-754 转换器,我将(手动)写入 testData.txt 文件,该文件使用表示浮点数 75.5 的位字符串读取;实际的 cout.write 确实表明位字符串也符合我的预期。但是,当我尝试使用联合将 char* 强制转换为浮点数时(正如我所见,这是完成此转换的典型方法),结果浮点数不是我期望的数字。

#include<climits>
#include<iostream>
#include<fstream>
#include<bitset>

int main( int, char** )
{

    std::ifstream inputFile( "testData.txt", std::ios_base::in | std::ios_base::binary );
    if( !inputFile ) std::cout << "Failed to open input file!" << std::endl;

    char buffer[ CHAR_BIT * sizeof(float) ];
    inputFile.read( buffer, CHAR_BIT * sizeof(float) );

    std::cout << "cout.write of input from file = ";
    std::cout.write( buffer, CHAR_BIT * sizeof(float) );
    std::cout << std::endl;

    union { float f; char* c; } fToCharStarUnion;

    fToCharStarUnion.c = buffer;
    std::bitset< sizeof(float) * CHAR_BIT > bits( std::string( fToCharStarUnion.c ) );
    std::cout << "fToCharStarUnion.f = " << fToCharStarUnion.f << " bits = " << bits << std::endl;

    inputFile.close();
    return 0;
}

运行this的返回结果为:

cout.write of input from file = 01000010100101110000000000000000
fToCharStarUnion.f = -1.61821e+38 bits = 01000010100101110000000000000000

我没有做一些基本的事情来使这项工作正常工作吗?

【问题讨论】:

    标签: c++ c casting bit-manipulation coercion


    【解决方案1】:

    你的联合需要包含一个字符数组而不是一个指针。

    union { float f; char c[sizeof(float)]; } float2char;
    

    您还必须担心字节顺序;是 c[0] 浮点数的指数端,或尾数的尾部。 (答案会因您的硬件而异 - Intel vs PPC 或 SPARC 或...)

    【讨论】:

    • 如上更改联合,使用 memcpy 调用将缓冲区放在联合的浮点变量上,但答案仍然不正确。我正在使用英特尔。我看到您没有将 sizeof(float) 乘以 CHAR_BIT ...我的问题可能与我的文件在 ascii 中手动写出有关吗?我认为这是由 ifstream ios_base::binary 标志处理的。
    • 我只需要与浮点数中的字节数一样多的字符 - 因此 sizeof(float) 是正确的。如果乘以 CHAR_BIT,在大多数机器上会分配一个 32 字节的值,但大多数浮点类型只有 4 字节长。
    • 我明白你在说什么(这是有道理的),但如果是这样的话,那么我认为我“读取”数据的方式有问题。如果我只读取 sizeof(float) 个字符,我只会得到一个单词,即 0100 而不是 01000010100101110000000000000000
    • @bpw1612:您有不同程度的混淆......您的数据由“1”和“0”字符组成的字符串,代表输入字符串每字节的 1 位信息。您必须将该 32 字节字符串压缩为 32 个连续位。然后,您可以考虑将数据提取为浮点数。但是,尽管您拥有所需数据的 8 倍,但您会遇到问题,而且世界上没有任何工会能帮上大忙。正如我之前所说,我认为@Potatoswatter 提供了一个很好的解决方案。我的基本观点(你不希望联合中的 char 指针)仍然有效,但是......
    • @bpw1612:好吧,我想我已经提交了一条评论,也许@Potatoswatter 的解决方案比我的更直接针对目标。我现在看不到它,所以也许我根本没有点击“添加”。
    【解决方案2】:

    您正在使用bitset 的构造函数将ASCII 转换为位。这会导致您的解码位位于bitset 对象而不是union 中。要从 bitset 中获取原始位,请使用 to_ulong 方法:

    #include<climits>
    #include<iostream>
    #include<fstream>
    #include<bitset>
    
    int main( int, char** )
    {
    
        std::ifstream inputFile( "testData.txt",
           std::ios_base::in | std::ios_base::binary );
        if( !inputFile ) std::cout << "Failed to open input file!" << std::endl;
    
        char buffer[ CHAR_BIT * sizeof(float) ];
        inputFile.read( buffer, CHAR_BIT * sizeof(float) );
    
        std::cout << "cout.write of input from file = ";
        std::cout.write( buffer, CHAR_BIT * sizeof(float) );
        std::cout << std::endl;
    
        union {
            float f[ sizeof(unsigned long)/sizeof(float) ];
            unsigned long l;
        } funion;
    
        funion.l = std::bitset<32>( std::string( buffer ) ).to_ulong();
        std::cout << "funion.f = " << funion.f[0]
           << " bits = " << std::hex <<funion.l << std::endl;
    
        inputFile.close();
        return 0;
    }
    

    这通常假定您的 FPU 以与 CPU 的整数部分相同的字节顺序运行,并且 sizeof(long) &gt;= sizeof(float)... 对 double 的保证较少,并且确实这个技巧更难移植到 32 位机器上64 位 FPU。

    编辑:现在我已经使联合的成员大小相等,我发现这段代码对字节序很敏感。解码后的float 将位于大端机器上数组的最后一个元素,小端机器上的第一个元素。 :v( 。也许最好的方法是尝试给联合的整数成员与 FP 成员一样多的位,并在获得to_ulong 后执行缩小转换。很难保持你看起来的可移植性标准在原始代码中进行拍摄。

    【讨论】:

    • 我已阅读您的回答,它确实完全解决了我的问题,非常感谢您。我会将此标记为已回答,但我想看看 Jonathan Leffler 是否在我之前提出了一些不同的东西。我也宁愿使用一个解决方案,它有一个字符数组和一个 unsigned long int 作为联合的另一个成员(因为目前尚不清楚如何将联合扩展到任何其他类型,而不是至少对我浮动但在 char[]如果它是微不足道的)。
    • @bpw:如果使用char[] 存储位数组,则每个char 对象存储8 位。如果您使用 long[] 存储位数组,则每个 long 对象存储 sizeof(long)*8 位。不幸的是,bitset 只会返回一个long 的比特给你,所以你基本上只能使用long[1]。这实际上是 bitset 的限制,您需要自己编写代码才能绕过它。
    • @bpw(来自其他线程):您至少可以将单个数据包塞入union。保证工会的所有成员拥有相同的地址。一系列数据包可以是一个指向缓冲区的联合指针序列。使用初始的int 来确定每个联合真正是什么类型的对象……这种行为由 C++ §9.5/1 定义并保证安全。但是,不要忘记对每个成员进行字节序转换。
    • 这实际上很有帮助。 @Jonathan Leffler:感谢您的帮助,您的 cmets 明确表示我将几个不同的问题混为一谈。
    猜你喜欢
    • 2011-12-20
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2020-11-06
    • 2019-08-25
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    相关资源
    最近更新 更多