2011-03-17 109 views
4

我必须做的是以二进制模式打开一个文件,该文件包含旨在被解释为整数的存储数据。我见过其他例子,如Stackoverflow-Reading “integer” size bytes from a char* array.,但我想尝试采取不同的方法(我可能只是固执或愚蠢:/)。我首先在十六进制编辑器中创建了一个简单的二进制文件,其内容如下。在C++中使用按位运算符将4个字符更改为int

00 00 00 47 00 00 00 17 00 00 00 41
如果12个字节被分成3个整数,这个(应该)等于71,23和65。

以二进制模式打开此文件并将4个字节读入一个字符数组后,如何使用按位操作使char [0]位成为int的前8位,依此类推,直到每个位char是int的一部分。


My integer = 00  00  00  00 
+   ^  ^  ^  ^
Chars  Char[0] Char[1] Char[2] Char[3] 
      00  00  00  47 


So my integer(hex) = 00 00 00 47 = numerical value of 71 

此外,我不知道我的系统的字节顺序是如何进入这里的,所以有什么我需要记住的吗?

这里是我到目前为止的代码片断,我只是不知道下一步要采取的步骤。


std::fstream myfile; 
    myfile.open("C:\\Users\\Jacob\\Desktop\\hextest.txt", std::ios::in | std::ios::out | std::ios::binary); 
    if(myfile.is_open() == false) 
    { 
     std::cout << "Error" << std::endl; 
    } 
    char* mychar; 
    std::cout << myfile.is_open() << std::endl; 
    mychar = new char[4]; 
    myfile.read(mychar, 4); 

我最终在处理阅读计划从一个文件中,也许一个自定义数据类型的最终浮动,但首先我需要得到更多熟悉如何使用按位运算。 谢谢。

+1

固执之外,你可以做到这一点通过读取int和再用ntohl使用() – 2011-03-17 02:43:13

+0

你的二进制文件是“big-endian”。所以只要你用big-endian的方式将它的字节转换为整数,你不需要担心计算机的字节序。 – aschepler 2011-03-17 02:44:16

+0

...直到您将您的代码移动到不同的系统,并尝试从大端系统读取数据。那么你会遇到问题。 – Thomi 2011-03-17 02:48:06

回答

19

你想按位左移运算:

typedef unsigned char u8; // in case char is signed by default on your platform 
unsigned num = ((u8)chars[0] << 24) | ((u8)chars[1] << 16) | ((u8)chars[2] << 8) | (u8)chars[3]; 

它是什么却将左参数位到左侧指定数目,从右边为馅加零。例如,2 << 1是4,因为2是二进制10和转换的一个向左给出100,这是4

这可以更写在一个更一般的形式循环:

unsigned num = 0; 
for (int i = 0; i != 4; ++i) { 
    num |= (u8)chars[i] << (24 - i * 8); // += could have also been used 
} 

的你的系统的字节顺序在这里并不重要;你知道文件中表示的字节顺序,这是恒定的(因此是可移植的),所以当你读入字节时,你知道如何处理它们。整数在CPU /内存中的内部表示可能与文件的内部表示不同,但在代码中逻辑按位操作与系统的字节顺序无关;最低有效位总是在右边,最左边(在代码中)。这就是为什么移位是跨平台的 - 它运行在逻辑位级别:-)

+0

干净的答案。谢谢这是帮助我解决我的永久性问题 – 2017-12-17 16:50:54

+0

它是否符合标志正常工作?不应该使用'unsigned char'? – ar2015 2018-02-04 23:10:22

+1

@ ar2015:你完全正确,这段代码不适用于带符号的字符,因为在完成移位之前,它们被隐式转换为具有相同(数字)值的'int'。我会添加一些演员。 – Cameron 2018-02-06 14:34:20

2

您是否想过使用Boost.Spirit来制作二进制解析器?当你开始的时候你可能会碰到一些学习曲线,但如果你想稍后扩展你的程序来读取浮点数和结构化类型,你将有一个很好的开始。

精神是非常有据可查的,是Boost的一部分。一旦你开始理解它的内幕和细节,真正令人难以置信的是你可以用它做什么,所以如果你有一点时间去玩,我真的建议看一看。否则,如果你希望你的二进制文件是“可移植的” - 也就是说你想能够在一个big-endian和一个little-endian的机器上读取它,你需要某种类型的字节顺序标记( BOM)。这将是你读的第一件事,之后你可以简单地逐字节读取你的整数。最简单的事情很可能是将它们读入工会(如果你知道你要读整数的大小),就像这样:

union U 
{ 
    unsigned char uc_[4]; 
    unsigned long ui_; 
}; 

将数据读入的uc_成员,围绕交换字节如果您需要更改字节顺序并从ui_成员中读取值。有没有移位等做 - 除了交换,如果你想更改端..

HTH

RLC

+0

那么我一直在使用大量的提升(线程,文件系统,随机,数学),所以我可能会尝试更熟悉精神类。 – contrapsych 2011-03-17 02:58:42