我已经编写了代码来保存一些具有像 CIOParams_b_t (参见声明)这样的结构的数据到文件并加载它们。数字字段(>1 位)从文件成功加载,但是布尔字段(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';
}
那么,你的函数当然就无法运行了。
您现在可能有尝试使用 8 个字节的想法,它可能会起作用。但这不是正确的解决方案。
您需要的是所谓的序列化。有许多免费的现成库可供使用。但对于您的少量数据,您也可以简单地覆盖您的类的插入器
<<
和提取 >>
运算符。
简短示例:
#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";
}