从 mmap() 读取时 ntohl() 返回 0

ntohl() returning 0 when reading from mmap()

晚上好,我正在尝试从 .img 文件中读取一些二进制信息。我可以从 ntohs() 中检索 16 位数字 (uint16_t),但是当我尝试使用 ntohl() 从同一位置检索时,它却给了我 0。

这是我程序的关键部分。

#include <iostream>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <cmath>

int fd;
struct blockInfo {
    long blockSize = 0;
    long blockCount = 0;
    long fatStart = 0;
    long fatBlocks = 0;
    long rootStart = 0;
    long rootBlocks = 0;
    long freeBlocks = 0;
    long resBlocks = 0;
    long alloBlocks = 0;
};


int main(int argc, char *argv[]) {

   fd = open(argv[1], O_RDWR);

   // Get file size
   struct stat buf{};
   stat(path, &buf);
   size_t size = buf.st_size;

   // A struct to hold data retrieved from a big endian image.
   blockInfo info;

   auto mapPointer = (char*) mmap(nullptr, size,
                     (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);

   info.blockSize = ntohs((uint16_t) mapPointer[12]);
   long anotherBlockSize = ntohl((uint32_t) mapPointer[11]);

   printf("%ld", info.blockSize); // == 512, correct
   printf("%ld", anotherBlockSize); // == 0, what?
}

我明白 blockSizeanotherBlockSize 不应该相等,但是 anotherBlockSize 至少应该是非零的,对吗?

别的,我去ntohs(pointer[16])访问数据,应该是return2,但也是returns 0,这是怎么回事?任何帮助将不胜感激。

auto mapPointer = (char*)  ...

这将 mapPointer 声明为 char *

... ntohl((uint32_t) mapPointer[11]);

您的明显意图是使用 mapPointer 从该位置检索一个 32 位值,一个 four-byte 值。

不幸的是,因为 mapPointer 是一个普通的 garden-variety char *,表达式 mapPointer[11] 的计算结果是一个单独的 char 值。一个字节。这就是代码从 mmaped 内存块中读取的内容,位于距块开头的第 11 个偏移处。 (uint32_t) 不会从引用的地址 mapPointer+11 读取 uint32_tmapPointer[11]mapPointer+11 读取单个 char 值,因为 mapPointer 是指向 char 的指针,将其转换为 uint32_t,并提供到 ntohl().

不,anotherBlockSize不一定是non-zero

info.blockSize = ntohs((uint16_t) mapPointer[12]);

此代码从相对于 mapPointer 的偏移量 12 读取一个字符,将其转换为 uint16_t 并对其应用 ntohs()。

long anotherBlockSize = ntohl((uint32_t) mapPointer[11]);

此代码从相对于 mapPointer 的偏移量 11 读取一个字符,将其转换为 uint32_t 并对其应用 ntohl()。

显然,您正在从映射内存中读取 non-overlapped 数据(不同的字符),因此您不应期望 blockSizeanotherBlockSize 连接。

如果你试图以不同的方式读取相同的内存(如uint32_t和uint16_t),你必须做一些指针转换:

info.blockSize = ntohs( *((uint16_t*)&mapPointer[12]));

请注意,此类代码通常依赖于平台。这种在 x86 上完美运行的转换可能在 ARM 上失败。