首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从mmap读取结构

从mmap读取结构
EN

Stack Overflow用户
提问于 2015-07-24 02:52:39
回答 1查看 404关注 0票数 0
代码语言:javascript
复制
typedef struct aaa {
  int a;
  int b;
  long ptr_to_st2; //offset from the beginning of the file.
} st1;

typedef struct bbb {
  int get;
  char it;
} st2;

我有一个使用mmap映射到内存的二进制文件。该文件包含文件开头的st1,然后是一些数据,然后是st2

代码语言:javascript
复制
unsigned char *filemap; //mmap
st1 *first=(st1 *)filemap;
st2 *second=(st2 *)filemap+first->ptr_to_st2;
printf("%c",second->it);

有人告诉我,这个代码不正确,违反了严格的混叠规则。编写这段代码的正确方法是什么?谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-07-24 03:54:09

简单地说,int有一个对齐的要求。假设您的机器上有两个sizeof (int),我们将您的内存看作一个块序列:

代码语言:javascript
复制
[a][a][b][b][c][c][d][d]...

我们可以将int存储在[a]块、[b]块等.基本上每隔一秒.但不是在他们之间。

实际上,在我们常用的家用机器上,我们可能能够在两者之间存储它们,但这需要付出性能代价;总线仍然对齐以检索满足对齐要求的整数,因此对于每一个错误对齐的整数,将通过总线进行两次检索。是不想要的.

在不常见的家用机器上(比如旧的苹果,甚至是那些我们不常用的程序,比如地球上的每一个路由器),这种不对齐的访问将导致类似于分段故障的情况,称为bus error绝对是不想要的!

如果您正确地序列化和反序列化您的信息(而不是仅仅使用类型转换来重新解释数组的一部分),您将不会看到任何这些问题。也就是说,逐字节转换结构,例如:

代码语言:javascript
复制
void serialise_st1(void *destination, st1 *source) {
    unsigned char *d = destination;
    unsigned long  s = (unsigned int) source->a;

    d[0] = s >> 8;
    d[1] = s;

    s = (unsigned int) source->b;
    d[2] = s >> 8;
    d[3] = s;

    s = source->ptr_to_st2;
    d[4] = s >> 24;
    d[5] = s >> 16;
    d[6] = s >> 8;
    d[7] = s;
}

注意到我是如何手动转换成每个字节的?由于需要处理符号,反序列化过程有点困难,但本质上是相反的:我们不是单独分配每个字节,而是单独访问每个字节。

代码语言:javascript
复制
void deserialise_st1(st1 *destination, void *source) {
    unsigned char *s = source;
    *destination = (st1) { .a = (s[0] <= 127 ? s[0] : -(256 - s[0])) * 0x0100
                              +  s[1],
                           .b = (s[2] <= 127 ? s[2] : -(256 - s[2])) * 0x0100
                              +  s[3],
                           .ptr_to_st2 = (s[4] <= 127 ? s[4] : -(256 - s[4])) * 0x01000000
                                       +  s[5] * 0x00010000
                                       +  s[6] * 0x00000100
                                       +  s[7] };
}

然后,根据您的示例进行调整:

代码语言:javascript
复制
unsigned char *filemap;
st1 first;
deserialise_st1(&first, filemap);

我将把它作为一个练习留给您编写deserialise_st2,但是可以随意询问您在这样做时是否有问题。

代码语言:javascript
复制
st2 second;
deserialise_st2(&second, filemap + st1.ptr_to_st2);

假设您的代码继续更新firstsecond,并且希望将这些更新推入您的filemap中,则需要知道它来自的偏移量.也就是说,您需要将filemap作为指向first的指针(first_ptr),将filemap + st1.ptr_to_st2作为指向second的指针(second_ptr).然后:

代码语言:javascript
复制
serialise_st1(first_ptr, &st1);
serialise_st2(second_ptr, &st2);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31601414

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档