晚上好,我正在尝试从.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?
}
我知道blockSize
和anotherBlockSize
不应该相等,但anotherBlockSize
至少应该是非零的,对吗?
还有别的,我去ntohs(pointer[16])
访问数据,该数据应返回2,但也返回0.这里发生了什么?任何帮助将不胜感激。
答案 0 :(得分:2)
不,anotherBlockSize
不一定非零
info.blockSize = ntohs((uint16_t) mapPointer[12]);
此代码相对于mapPointer从offset 12 读取一个char,将其强制转换为uint16_t并将ntohs()应用于它。
long anotherBlockSize = ntohl((uint32_t) mapPointer[11]);
此代码相对于mapPointer从offset 11 读取一个char,将其强制转换为uint32_t并将ntohl()应用于它。
显然,您正在从映射的内存中读取非重叠数据(不同的字符),因此您不应期望连接blockSize
和anotherBlockSize
。
如果你试图以不同的方式读取相同的内存(如uint32_t和uint16_t),你必须做一些指针转换:
info.blockSize = ntohs( *((uint16_t*)&mapPointer[12]));
请注意,此类代码通常与平台有关。这种在x86上完美运行的转换可能在ARM上失败。
答案 1 :(得分:1)
auto mapPointer = (char*) ...
这声明mapPointer
为char *
。
... ntohl((uint32_t) mapPointer[11]);
这里你明显的意图是使用mapPointer
从这个位置检索32位值,一个四字节值。
不幸的是,因为mapPointer
是一个简单的花园种类char *
,所以表达式mapPointer[11]
会评估为单个孤独的char
值。一个字节。这就是代码从mmap
内存块读取的内容,在块起始的第11个偏移处。 (uint32_t)
未从引用的地址uint32_t
中读取mapPointer+11
。 mapPointer[11]
从char
读取一个mapPointer+11
值,因为mapPointer
是指向char
的指针,将其转换为uint32_t
,并且至ntohl()
。