2010-02-18 80 views
1

我無法使下面的代碼正常工作。使用一個在線的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; 
} 

運行此的返回結果是:

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

有一些基本的東西我沒有做這將正確地做這項工作?

回答

3

您正在使用構造函數bitset將ASCII轉換爲位。這會導致您的解碼位位於bitset對象中,而不是union。要獲取原始位出位集合的,使用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) >= sizeof(float) ......爲double少保障,的確,這個技巧難以使用64位FPU的32位機器進行移植。

編輯︰現在,我已經使聯盟的成員大小相等,我看到這段代碼是敏感的endianness。解碼後的float將位於大端機器上的陣列的最後一個元素上,這是小端的第一個元素。 :v(。也許最好的辦法是試圖讓聯合的整數成員與FP成員一樣多,並且在得到to_ulong後執行縮小的轉換。很難保持你似乎是可移植性的標準在原始代碼中拍攝

+0

我讀過你的回答,它確實完全解決了我的問題,所以非常感謝你。我會把這個標記爲答案,但我想看看Jonathan Leffler在我做之前是否提出了不同的東西。我寧願使用一個字符數組副作爲unsigned long int的解決方案作爲union的另一個成員(因爲不清楚如何將union擴展爲除了float之外的任何其他類型,至少在char []中它是微不足道的)。 – bpw1621 2010-02-18 20:00:34

+0

@bpw:如果使用'char []'存儲位數組,每個'char'對象存儲8位數據。如果使用'long []'存儲位數組,每個'long'對象存儲sizeof(long)* 8位。不幸的是,'bitset'只會向你返回一個'long'的值,所以你基本上被限制在'long [1]'中。這實際上是'bitset'的限制,你需要自己編碼才能解決它。 – Potatoswatter 2010-02-18 20:06:56

+0

@bpw(來自其他線程):至少可以將單個數據包塞入「union」。工會的所有成員都保證有相同的地址。一系列數據包可以是一系列聯合指針進入緩衝區。使用該初始的「int」來確定每個聯合實際是什麼類型的對象...此行爲由C++§9.5/ 1定義並保證安全。但是,不要忘記對每個成員執行endian轉換。 – Potatoswatter 2010-02-18 20:30:12

4

你的聯合需要包含一個char數組而不是指針。

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

您還將不得不擔心排序;是c [0]是浮點數的指數末尾,或是尾數的尾部。 (答案會根據您的硬件而有所不同 - Intel與PPC或SPARC或...)

+0

如上所述更改了union,使用memcpy調用將緩衝區放在union的float變量上,但答案仍然不正確,我正在使用Intel,我看到您沒有乘法CHAR_BIT的sizeof(float)...有可能是我的問題與我的文件被手寫在ascii中有關嗎?我認爲這是由ifstream ios_base :: binary標誌處理的,儘管如此。 – bpw1621 2010-02-18 19:40:33

+0

我只有需要儘可能多的字符,因爲float中的字節數 - 因此sizeof(float)是正確的。如果您乘以CHAR_BIT,則在大多數機器上將分配一個32字節的值,但大多數float類型只有4個字節長。 – 2010-02-18 19:47:09

+0

我明白你在說什麼(也是有道理的),但如果是這種情況,那麼我認爲我正在「讀」數據的方式有問題。如果我只讀了sizeof(浮動)字符,我只能得到一個字,即0100而不是01000010100101110000000000000000 – bpw1621 2010-02-18 19:52:34