了解二进制转换
Understanding binary conversions
我正在编写一个资源文件,我想插入来自各种常见文件(例如.JPG、.BMP)的一组数据,我希望它是二进制的。稍后,我将编写一些代码来检索这些按索引组织的数据,这就是我目前所得到的:
float randomValue = 23.14f;
ofstream fileWriter;
fileWriter.open("myFile.dat", ios::binary);
fileWriter.write((char*)&randomValue, sizeof(randomValue));
fileWriter.close();
//With this my .dat file, when opened in notepad has "B!¹A" in it
float retrieveValue = 0.0f;
ifstream fileReader;
fileReader.open("myFile.dat", ios::binary);
fileReader.read((char*)&retrieveValue, sizeof(retrieveValue));
fileReader.close();
cout << retrieveValue << endl; //This gives me exactly the 23.14 I wanted, perfect!
虽然这很有效,但我想了解那里到底发生了什么。我正在将randomValue的地址转换为char*,并将该地址中的值写入文件?
我很好奇,因为我需要为数组做这件事,但我做不到:
int* myArray = new int[10];
//fill myArray values with random stuff
fileWriter.open("myFile.dat", ios::binary);
fileWriter.write((char*)&myArray, sizeof(myArray));
fileWriter.close();
据我所知,这只是在文件中写入第一个地址值,而不是所有数组。因此,为了进行测试,我试图简单地将一个变量转换为一个char*,然后将其写入一个文件,再转换回该变量,看看我是否正确地检索了值,所以我使用了这个:
int* intArray = new int[10];
for(int i = 0; i < 10; i++)
{
cout << &intArray[i]; //the address of each number in my array
cout << intArray[i]; //it's value
cout << reinterpret_cast<char*>(&intArray[i]); //the char* value of each one
}
但出于某种原因,我不知道,当我运行这个代码时,我的电脑会"哔哔"作响。在数组中,我还将这些值保存为char*,并试图转换回int,但我没有得到预期的结果,我得到了一些非常长的值。类似于:
float randomValue = 23.14f;
char* charValue = reinterpret_cast<char*>(&randomValue);
//charValue contains "B!¹A" plus a bunch of other (un-initiallized values?) characters, so I'm guessing the value is correct
//Now I'm here
我想把charValue转换回randomValue,我该怎么做?
编辑:下面的答案中有一些有价值的信息,但它们并不能解决我的(原始)问题。我测试这些类型的转换是因为我正在做一个代码,我会选择一堆资源文件,如BMP、JPG、MP3,并将它们保存在一个.DAT文件中,该文件是根据一些我还没有完全弄清楚的标准组织的。
稍后,我将使用这个资源文件来读取这些内容,并将其加载到我正在编写的程序(游戏)中。
我仍在考虑标准,但我想知道是否有可能这样做:
//In my ResourceFile.DAT
[4 bytes = objectID][3 bytes = objectType (WAV, MP3, JPG, BMP, etc)][4 bytes = objectLength][objectLength bytes = actual objectData]
//repeating this until end of file
然后在读取资源文件的代码中,我想做这样的事情(未经测试):
ifstream fileReader;
fileReader.open("myFile.DAT", ios::binary);
//file check stuff
while(!fileReader.eof())
{
//Here I'll load
int objectID = 0;
fileReader((char*)&objectID, 4); //read 4 bytes to fill objectID
char objectType[3];
fileReader(&objectType, 3); //read the type so I know which parser use
int objectLength = 0;
fileReader((char*)&objectLength, 4); //get the length of the object data
char* objectData = new char[objectLength];
fileReader(objectData, objectLength); //fill objectData with the data
//Here I'll use a parser to fill classes depending on the type etc, and move on to the next obj
}
目前,我的代码正在处理原始文件(BMP、WAV等)并将它们填充到类中,我想知道如何将这些文件中的数据保存到二进制数据文件中。例如,我的管理BMP数据的类具有以下内容:
class FileBMP
{
public:
int imageWidth;
int imageHeight;
int* imageData;
}
当我加载它时,我调用:
void FileBMP::Load(int iwidth, int iheight)
{
int imageTotalSize = iwidth * iheight * 4;
imageData = new int[imageTotalSize]; //This will give me 4 times the amount of pixels in the image
int cPixel = 0;
while(cPixel < imageTotalSize)
{
imageData[cPixel] = 0; //R value
imageData[cPixel + 1] = 0; //G value
imageData[cPixel + 2] = 0; //B value
imageData[cPixel + 3] = 0; //A value
cPixel += 4;
}
}
因此,我有一个包含每个像素[RGBA]格式值的一维数组,稍后我将使用它在屏幕上绘制。我希望能够将这个数组保存为我计划的二进制数据格式,如上所述,然后读取它并填充这个数组。
我认为这对这样的代码要求太高了,所以我想了解我需要知道什么才能将这些值保存到二进制文件中,然后读回以填充它
抱歉发了这么长的帖子!
edit2:我通过第一次编辑解决了问题。。。谢谢你的宝贵信息,我也知道了我想要什么!
通过使用&运算符,您将获得一个指向变量内容的指针(将其视为一个内存地址)。
float a = 123.45f;
float* p = &a; // now p points to a, i.e. has the memory address to a's contents.
char* c = (char*)&a; // c points to the same memory location, but the code says to treat the contents as char instead of float.
当你给出(char*)&对于write()的randomValue,您只需告诉"获取具有字符数据的内存地址,并从中写入sizeof(randomValue)个字符"。您不是在写地址值本身,而是在写内存中该位置的内容("原始二进制数据")。
cout << reinterpret_cast<char*>(&intArray[i]); //the char* value of each one
这里需要给出char*类型的数据,以null char(零)结尾。但是,您提供的是浮点值的原始字节。你的程序可能会在这里崩溃,因为cout会输入字符,直到它找到终止符字符——它可能很快就找不到。
float randomValue = 23.14f;
char* charValue = reinterpret_cast<char*>(&randomValue);
float back = *(float*)charValue;
编辑:要保存二进制数据,只需提供数据并写入()即可。不要使用<lt;运算符用ofstream/cout重载。例如:
int values[3] = { 5, 6, 7 };
struct AnyData
{
float a;
int b;
} data;
cout.write((char*)&values, sizeof(int) * 3); // the other two values follow the first one, you can write them all at once.
cout.write((char*)&data, sizeof(data)); // you can also save structs that do not have pointers.
如果您要编写structs,请查看#pragma-pack编译器指令。编译器会将变量对齐(使用填充)到一定的大小(int),这意味着以下结构实际上可能需要8个字节:
#pragma pack (push, 1)
struct CouldBeLongerThanYouThink
{
char a;
char b;
};
#pragma pack (pop)
此外,不要写入指针值本身(如果结构中有指针成员),因为从文件中读回后,内存地址不会指向任何有意义的数据。始终写入数据本身,而不是指针值。
发生的情况是,您正在复制内部将数据表示形式复制到文件中,然后将其复制回进入内存,只要程序执行写作是用相同版本的编译器编译的,使用相同的选项。否则,它可能会也可能不会工作,取决于你无法控制的任何数量的事情。
我不清楚你想做什么,但格式.jpg和.bmp通常指定它们想要的格式不同的类型,你必须尊重这种格式。
不清楚你真正想做什么,所以我不能推荐一种解决你真正问题的方法。但是,如果运行程序真的在程序中引起哔哔声或任何其他奇怪的行为,我不会感到惊讶。
int* intArray = new int[10];
for(int i = 0; i < 10; i++)
{
cout << reinterpret_cast<char*>(&intArray[i]);
}
上面new
返回的内存未初始化,但您正在尝试打印,就好像它是一个以null结尾的字符串一样。未初始化的内存可能具有钟形字符(当将打印到终端时会引起嘟嘟声)或任何其他值,包括它可能没有null终止,并且流中的插入运算符将溢出缓冲区,直到它找到null或您的程序访问无效内存时崩溃。
代码中还有其他不正确的假设,例如给定int *p = new int[10];
,表达式sizeof(p)
将是体系结构中指针的大小,而不是整数大小的10倍。
- visual在c++中将十进制数转换为二进制数
- C++十进制到二进制,如何转换
- 如何将一个ostringstream十六进制字符串字符对转换为单个unit8t等价的二进制值
- C++从二进制转换为十进制数
- 错误 C2679:二进制"<<":未找到采用类型 'std::string_view' 的右侧操作数的运算符(或者没有可接受的转换)
- 我编写了代码将十进制分数转换为其二进制等效数.它编译得很好,但在执行时挂起
- C2678 二进制 '==':未找到采用 'Card' 类型左操作数的运算符(或者没有可接受的转换)
- 如何在 O(n) 中将二进制和转换为二进制
- 我写的 ASCII 到二进制转换器C++向后显示二进制,如何使其正确显示?
- 十进制到二进制转换器 c++
- 在C++中将结构转换和存储为二进制
- 从二进制流中读取时,将双精度变量的地址转换为 char* 意味着什么?
- 如何在C ++中将二进制字符串128位转换为十进制字符串?
- 如何将二进制文件头示例代码 (C++/C#) 转换为 Python?
- 二进制 '==':未找到采用 'Enemy' 类型左侧操作数的运算符(或者没有可接受的转换)
- 将二进制转换为十进制,我如何要求用户仅输入二进制
- QTextStream的操作数到二进制的转换无效
- 在c++中读取和转换二进制数据
- c++转换二进制到十进制从字符串输入
- 计算器转换二进制到浮点值-我做错了什么