C中结构之间的额外填充

C中结构之间的额外填充,c,gcc,memory,C,Gcc,Memory,我有C语言的结构: typedef struct Node { int data; // 4 bytes int + 4 bytes for alignment struct Node* prev; // 8 bytes pointer struct Node* next; // 8 bytes pointer } Node; 此结构的大小为24字节(8+8+8)。当我使用sizeof(节点)时,编译器还显示24个字节 但是,当我在堆上创建两个或多个结构(一个接一个)并

我有C语言的结构:

typedef struct Node {
    int data; // 4 bytes int + 4 bytes for alignment
    struct Node* prev; // 8 bytes pointer
    struct Node* next; // 8 bytes pointer
} Node;
此结构的大小为24字节(8+8+8)。当我使用sizeof(节点)时,编译器还显示24个字节

但是,当我在堆上创建两个或多个结构(一个接一个)并查看它们的内存位置时,每个节点结构之间有8个字节的间隙。 例如:

11121344 (the 1st Node address)
11121376 (the 2nd Node address) // 376-344 = 32-24 = 8 extra bytes
11121408 (the 3rd Node address) // 408-376 = 32-24 = 8 extra bytes
您能解释一下为什么编译器通过在节点之间添加8个字节来分隔节点结构吗

您能解释一下为什么编译器通过在节点之间添加8个字节来分隔节点结构吗

这是巧合。没有关于如何为任何
malloc()调用序列安排内存的规则

地址可以以固定的间隔递增,也可以以不同的间隔递减,(看似)随机

如果需要固定的相对地址,请使用数组

struct Node arr[3];
ptrdiff_t delta10 = &arr[1] - &arr[0];
ptrdiff_t delta20 = &arr[2] - &arr[0];
ptrdiff_t delta21 = &arr[2] - &arr[1];
if (delta10 != delta21) /* cannot happen */;
或者同时分配一组元素(可能使用
realloc()

struct Node *elements = malloc(3 * sizeof *elements);
ptrdiff_t delta10 = &elements[1] - &elements[0];
ptrdiff_t delta20 = &elements[2] - &elements[0];
ptrdiff_t delta21 = &elements[2] - &elements[1];
if (delta10 != delta21) /* cannot happen */;
free(elements);

您的观察可能有两个原因:

  • C标准要求
    malloc
    始终返回具有最大对齐度的内存块,以防止对齐问题,无论您为什么分配
  • malloc
    通过使用某种数据结构在内部管理内存块。根据实现的不同,它会向每个内存块添加额外的信息,以供内部使用。例如,malloc可以管理链表中的内存块,然后它将要求每个块持有指向下一个块的额外指针
  • 最大对齐取决于所使用的体系结构和编译器/
    malloc
    -实现

    对于您的案例和假设glibc,直接从
    glibc/malloc.c
    的文档中获取:

     Alignment:                              2 * sizeof(size_t) (default)
           (i.e., 8 byte alignment with 4byte size_t). This suffices for
           nearly all current machines and C compilers. However, you can
           define MALLOC_ALIGNMENT to be wider than this if necessary.
      Minimum overhead per allocated chunk:   4 or 8 bytes
           Each malloced chunk has a hidden word of overhead holding size
           and status information.
      Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
                  8-byte ptrs:  24/32 bytes (including, 4/8 overhead)
    
    因此,在您的情况下,
    malloc
    将与
    2*sizeof(size\u t)=
    16字节对齐


    还要注意提到的“隐藏开销”。这种开销是由于存储用于内存管理的其他内部信息造成的…

    我猜原因是为了使结构字对齐。它有助于内存访问。如果您在堆上创建了它们,则所有赌注都会偏离它们被分配的内存地址。秘密在于您如何“创建两个或多个结构”。这是一个数组吗?如果不是,为什么期望内存地址彼此有任何关系?
    malloc(sizeof(Node)*3)
    是一个由3个结构组成的数组,您希望在其中使用某些相对地址<代码>malloc(sizeof(Node));malloc(sizeof(Node));malloc(sizeof(Node))
    是3个完全不相关的对象,每个对象都可能在任何地方。Malloc还使用一些内存进行内部记账(有时还放金丝雀来检测损坏)。有几种可能的策略,其中一些可能会以这种方式暴露自己。这种行为不太可能是随机偶然的“巧合”。这可能是C标准要求
    malloc
    返回与任何具有基本对齐要求的对象适当对齐的内存,或内存管理功能设计的结果。