簡體   English   中英

C++:位字段不能正確使用 1 位字段

[英]C++: bit-fields not works correctley with 1-bit fields

我已經編寫了代碼來保存一些數據,其結構類似於 CIOParams_b_t(請參閱聲明)以歸檔和加載它們。 數字字段(> 1 位)從文件中成功加載,但是 boolean 字段(1 位)加載有錯誤,可能是錯誤的。

保存數據程序:

//...
        std::ofstream file;
        file.open(path, std::fstream::out|std::ios::binary|std::ofstream::trunc);
//...
        union {
            CIOParams_b_t params_b_t;
            char raw[6];
        } p_data;
        p_data.params_b_t.scr_width = params.scr_width;
        p_data.params_b_t.scr_hight = params.scr_hight;
        p_data.params_b_t.bits = static_cast<int>(params.bits);
        p_data.params_b_t.brightness = params.brightness;
        p_data.params_b_t.contrast = params.contrast;

        p_data.params_b_t.fullscr = getFlag(params.flags, FLAG_FULLSCREEN)?1:0;
        p_data.params_b_t.vsync = getFlag(params.flags, FLAG_VSYNC)?1:0;
        p_data.params_b_t.mipmap = getFlag(params.flags, FLAG_MIPMAP)?1:0;
        p_data.params_b_t.skybox = getFlag(params.flags, FLAG_SKYBOX)?1:0;

        file.write(p_data.raw, 6);
//...

加載數據過程:

//...
        std::ifstream file(path);
//...
        union {
            CIOParams_b_t params_b_t;
            char raw[6];
        } p_data;
        file.read(p_data.raw, 6);

        retVal.scr_width = p_data.params_b_t.scr_width;
        retVal.scr_hight = p_data.params_b_t.scr_hight;
        retVal.bits = static_cast<CIOParams::cbits>(p_data.params_b_t.bits);
        retVal.brightness = p_data.params_b_t.brightness;
        retVal.contrast = p_data.params_b_t.contrast;

        setFlag(&retVal.flags, FLAG_FULLSCREEN, p_data.params_b_t.fullscr==1?true:false);
        setFlag(&retVal.flags, FLAG_VSYNC, p_data.params_b_t.vsync==1?true:false);
        setFlag(&retVal.flags, FLAG_MIPMAP, p_data.params_b_t.mipmap==1?true:false);
        setFlag(&retVal.flags, FLAG_SKYBOX, p_data.params_b_t.skybox==1?true:false);

        file.close();
//...

結構聲明:

struct CIOParams
{
    unsigned short int scr_width;
    unsigned short int scr_hight;
    unsigned char brightness;
    unsigned char contrast;
    enum cbits
    {
        b8 = 0,
        b16,
        b32,
        b64
    } bits;
    unsigned char flags;
    bool hasError = false;
};

struct CIOParams_b_t
{
    unsigned scr_width  : 10;
    unsigned scr_hight  : 10;
    unsigned bits       : 2;
    unsigned fullscr    : 1;
    unsigned vsync      : 1;
    unsigned brightness : 8;
    unsigned contrast   : 8;
    unsigned mipmap     : 1;
    unsigned skybox     : 1;
    unsigned __unused   : 6;
};

注意:函數 setFlag 和 getFlag 運行成功。 無論如何,他們在單元測試中表現良好。

問題來自字節邊界的填充。 所以,您認為您的“CIOParams_b_t”類型是 6 個字節長。 但這並不能保證。 在我的環境中,編譯器將其填充為 8 字節長度:

#include <iostream>
struct CIOParams_b_t
{
    unsigned scr_width : 10;
    unsigned scr_hight : 10;
    unsigned bits : 2;
    unsigned fullscr : 1;
    unsigned vsync : 1;
    unsigned brightness : 8;
    unsigned contrast : 8;
    unsigned mipmap : 1;
    unsigned skybox : 1;
    unsigned __unused : 6;
};

int main() {
    CIOParams_b_t c;
    std::cout << sizeof(c) << '\n';

}

在此處輸入圖像描述

那你的function當然不行了。

您現在可能有嘗試使用 8 個字節的想法,它可能會奏效。 但這不是正確的解決方案。

您需要的是所謂的序列化。 有許多免費的即用型庫。 但是對於您的少量數據,您也可以簡單地為您的 class 覆蓋插入器<<和提取>>運算符。

簡短示例:

#include <iostream>
#include <string>
#include <fstream>

struct CIOParams_b_t
{
    unsigned scr_width : 10;
    unsigned scr_hight : 10;
    unsigned bits : 2;
    unsigned fullscr : 1;
    unsigned vsync : 1;
    unsigned brightness : 8;
    unsigned contrast : 8;
    unsigned mipmap : 1;
    unsigned skybox : 1;
    unsigned __unused : 6;

    friend std::istream& operator >> (std::istream& is, CIOParams_b_t& c) {
        unsigned tmp;
        is >> tmp; c.scr_width = tmp;
        is >> tmp; c.scr_hight = tmp;
        is >> tmp; c.bits = tmp;
        is >> tmp; c.fullscr = tmp;
        is >> tmp; c.vsync = tmp;
        is >> tmp; c.brightness = tmp;
        is >> tmp; c.contrast = tmp;
        is >> tmp; c.mipmap = tmp;
        is >> tmp; c.skybox = tmp;
        return is;
    }
    friend std::ostream& operator << (std::ostream& os, const CIOParams_b_t& c) {
        return os << c.scr_width << '\n' << c.scr_hight << '\n' << c.bits << '\n' << c.fullscr << '\n' << c.vsync << '\n'
            << c.brightness << '\n' << c.contrast << '\n' << c.mipmap << '\n' << c.skybox << '\n';
    }
};


const std::string fileName{ "tmp.txt" };
int main() {

    CIOParams_b_t c1{1,3,3,0,1,4,5,0,1,0};

    if (std::ofstream outFileStream{ fileName }; outFileStream)
        outFileStream << c1;
    else
        std::cerr << "\nError: Could not open '" << fileName << "' for writing\n";


    if (std::ifstream inFileStream{ fileName }; inFileStream) {
        CIOParams_b_t c2{};
        inFileStream >> c2;
        std::cout << c2;
    }
    else
        std::cerr << "\nError: Could not open '" << fileName << "' for reading\n";
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM