从内存缓冲区读取结构会引发编译器错误和段错误

Reading a struct from a memory buffer raises a compiler error and segfault

在下面的代码中,我尝试将 struct 存储在原始内存缓冲区中。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

typedef struct {
  int a;
} Thing;

int main(void) {
  uint8_t* buffer = malloc(sizeof(Thing) * 200);

  Thing thing;
  thing.a = 80;

  memcpy(buffer, &thing, sizeof(Thing));

  Thing* thing_ptr = (Thing*) buffer[0];

  return 0;
}

但是,我收到以下编译器警告:

warning: cast to 'Thing *' from smaller integer type
      'uint8_t' (aka 'unsigned char') [-Wint-to-pointer-cast]
      Thing* thing_ptr = (Thing*) buffer[0]

此外,当我尝试在最后取消引用 thing_ptr 时:

printf("%d\n", thing_ptr->a);

我得到一个segmentation fault

两个问题:

一个。 Thing* thing_ptr = (Thing*) buffer[0]; 怎么了?为什么会引发错误?

乙。段错误的原因是什么?

Thing* thing_ptr = (Thing*) buffer[0];

不正确。

变量buffer是一个uint8_t *,所以buffer[0]是一个uint8_t。在这种情况下,buffer[0] 等同于 *buffer.

有两种选择:

你可以取buffer[0]的地址:

Thing* thing_ptr = (Thing*) &buffer[0];

在这种情况下,这没有多大意义,但在其他一些情况下它可以阐明意图。

在我看来,更好的选择是删除 [0]:

Thing* thing_ptr = (Thing*) buffer;

这清楚地表明您正在将 buffer 中的值从类型 uint8_t * 转换为 Thing *


[-Wint-to-pointer-cast] 警告表示您正在从不同大小的整数类型转换为指针。这种类型的转换通常没有意义。

出现此类警告的原因之一是为了防止出现类似您遇到的问题。


您的版本导致段错误,因为您将 uint8_tbuffer[0](可能是 080,取决于字节顺序)解释为指针。这可能是个人计算机上的无效指针,取消引用它会导致您的平台出现段错误。