【问题标题】:Using bitwise operators in C++ to change 4 chars to int在 C++ 中使用位运算符将 4 个字符更改为 int
【发布时间】:2011-07-17 02:19:35
【问题描述】:

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

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

另外,我不知道我的系统的字节序是如何在这里发挥作用的,所以我需要记住什么吗?

这是我目前所拥有的代码 sn-p,我只是不知道接下来要采取的步骤。


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 &lt&lt "Error" &lt&lt std::endl;
    }
    char* mychar;
    std::cout &lt&lt myfile.is_open() &lt&lt std::endl;
    mychar = new char[4];
    myfile.read(mychar, 4);

我最终计划处理从文件中读取浮点数,最终可能是自定义数据类型,但首先我只需要更熟悉使用按位运算即可。 谢谢。

【问题讨论】:

  • 除了固执之外,您可以通过读取 int 并使用 ntohl() 来做到这一点
  • 你的二进制文件是“big-endian”。所以只要你用大端的方式把它的字节转换成整数,你就不用担心计算机的字节序了。
  • ...直到您将代码移动到不同的系统,并尝试从大端系统中读取数据。那么你就会遇到问题。
  • @Thomi:因此大卫打电话给ntohl() 以防止这种情况发生

标签: c++ char int bit-manipulation


【解决方案1】:

你想要按位左移运算符:

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 &lt;&lt; 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/内存中整数的内部表示可能与文件的不同,但代码中对它的逻辑按位操作与系统的字节序无关;最低有效位总是在右边,最高在左边(在代码中)。这就是为什么 shift 是跨平台的——它在 logical 位级别上运行 :-)

【讨论】:

  • 干净的答案。谢谢,这可以帮助我解决我的字节序问题
  • 它与标志一起正常工作吗?不应该使用unsigned char
  • @ar2015:你说得对,此代码不适用于有符号字符,因为它们在转换完成之前已隐式转换为具有相同(数字)值的int。我会添加一些演员表。
  • (24 - i * 8) 需要记住运算符优先级,并假定特定的实现定义的事物。我更喜欢((sizeof(unsigned) - i) * CHAR_BITS)这里
  • @Caleth:虽然我同意 CHAR_BITS 在库代码中更好,但为了保持示例简单,我认为假设 8 位字符是相当安全的;其他类型也必须更改,以免它们的
【解决方案2】:

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

Spirit 有很好的文档记录,是 Boost 的一部分。一旦你开始了解它的来龙去脉,你能用它做什么真是令人难以置信,所以如果你有时间玩它,我真的建议你看看。

否则,如果您希望您的二进制文件是“可移植的” - 即您希望能够在大端和小端机器上读取它,您将需要某种字节顺序标记(BOM )。那将是您阅读的第一件事,之后您可以简单地逐字节读取整数。最简单的事情可能是将它们读入一个联合(如果您知道要读取的整数的大小),如下所示:

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

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

HTH

rlc

【讨论】:

  • 嗯,我一直在使用大量的提升(线程、文件系统、随机、数学),所以我可能会尝试更熟悉精神类。
猜你喜欢
  • 1970-01-01
  • 2014-11-29
  • 1970-01-01
  • 2011-05-19
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 2013-04-23
相关资源
最近更新 更多