2

基本上我正在阅读一种二进制格式,其中 4 个字节指定要遵循的字符串的大小。所以我想将我从缓冲区读取的 4 个字符转换为 1 个整数。

这就是我所拥有的。

int FileReader::getObjectSizeForMarker(int cursor, int eof, char * buffer) {
  //skip the marker and read next 4 byes
  int cursor = cursor + 4; //skip marker and read 4
  char tmpbuffer[4] = {buffer[cursor], buffer[cursor+1], buffer[cursor+2], buffer[cursor+3]};
  int32_t objSize = tmpbuffer;
  return objSize;

}

想法?

4

5 回答 5

5

手动解包非常容易:

unsigned char *ptr = (unsigned char *)(buffer + cursor);
// unpack big-endian order
int32_t objSize = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
于 2012-10-07T02:06:21.060 回答
4

假设这些是存储的 MSB(即大端)。

unsigned char *p = (unsigned char*)buffer + cursor;
uint32_t uiSize = (unsigned int)*p <<24 |
                  (unsigned int)*(p+1) << 16 |
                  (unsigned int)*(p+2) << 8 |
                  (unsigned int)*(p+3);

组装后将结果转换为带符号的 int 。我知道这很可怕,但我的打字技巧也是如此。

注意:老实说,我不记得隐式向上转换是否将符号从 char 扩展为 int,但如果确实如此,并且此处的任何单个字节被或一起是最高位点亮的,你如果 *p 不是,可能会感到惊讶。因此,看似偏执的 unsigned cast-o-festival,以及仅完全组装后才转换为 signed-int 的后续行动。

于 2012-10-07T02:05:35.660 回答
2

这应该可以解决问题:

objSize = 0;
for (int i = 0; i < 4; ++ i)
    objeSize += ((int)tmpbuffer[i]) << (8 * i);

或者

objSize = 0;
for (int i = 0; i < 4; ++ i)
    objeSize += ((int)tmpbuffer[i]) << (8 * (3 - i));

正如 nneonneo 指出的那样,对于大端

于 2012-10-07T01:56:58.500 回答
-1

您所拥有的应该可以正常工作,但要替换它

int32_t objSize = tmpbuffer;

为了这

int32_t objSize = *((int32_t*)tmpbuffer);
  • 它必须在相同的架构中存储和读取。
于 2012-10-07T01:58:23.380 回答
-1

您可以使用该ntohl功能将网络字节顺序转换为主机字节顺序。无需重新发明轮子。这还具有一些可移植性的优点,并且只要使用正确的标头,就可以在大端和小端操作系统上工作。下面是一个 Windows 示例,但该功能在 Linux 上也可用:

#include <winsock.h>
#include <iostream>

int main()
{
    char buffer[] = "MARK\x00\x00\x00\x08";
    // Point to the 4-byte network (big-endian) order value.
    unsigned long * size = (unsigned long *)(buffer + 4);
    // Dereference and convert it.
    std::cout << ntohl(*size) << std::endl;
    return 0;
}

输出:

8
于 2012-10-07T05:19:40.047 回答