为什么应用于具有灵活数组成员的结构的 sizeof 不会产生分配的空间?

问题描述

我正在尝试在 C 中创建一个灵活的结构,以便在为它分配内存时,我不会像将数据类型声明为大小常量那样浪费空间。但是,我的程序没有正确分配空间。 printf 语句显示 sizeof 生成 8,即使我分配了更多空间。为什么?

typedef struct node {
    struct node *next;
    char word[];
} node;

...

    while (fscanf(input,"%s",word) == 1) {
        struct node *w = malloc(sizeof(*w) + 1 + sizeof(strlen(word));
        if (w == NULL) {
            printf("Memory Error\n");
            return false;
        }
        strcpy(w->word,word);
        printf("%lu\n",sizeof(*w));
    }

解决方法

another answer on SO中所述,结构的大小就像省略了灵活的数组成员(除了填充问题)。因此,在计算 sizeof(*w) 时,只有 struct node * next 字段对大小有影响。由于您(大概)使用的是 64 位平台,因此根据您的观察,计算结果为 8 个字节。

,

sizeof 不确定作为其操作数的对象的大小。它只决定其操作数的类型的大小。

例如,如果您使用 int 分配一个 1000 int *x = malloc(1000 * sizeof(int)); 的数组,则 sizeof *x 返回一个 int 的大小,因为 {{1} 的类型} 是 *x

对于 int,其中 sizeof *w 是具有灵活数组成员的结构,w 返回类型的大小,即结构的基本大小。它不知道您为该结构分配了多少额外空间。

结构的基本大小与结构在没有灵活数组成员的情况下定义的大小相同,除了它可能有更多的填充(如果灵活数组元素类型比其他类型需要更多对齐,则可能需要填充)结构中的东西)。

所以,在 sizeof 之后,struct node *w = malloc(sizeof(*w) + 1 + sizeof(strlen (word)); 只会给你 sizeof *w,而不是分配的大小。

,

正如 Eric 所指出的,sizeof 计算其操作数类型的大小。除了 sizeof(char[fun()]) 和可变长度数组等边界情况外,此评估在编译时执行。即使在这些情况下,大小也与对象本身无关,仅在定义对象的范围内可用。 node 末尾的灵活数组不包含在 node 对象的大小中,分配的大小取决于每个实例。

顺便说一句,发布的代码没有分配正确的大小(它实际上没有编译):malloc(sizeof(*w) + 1 + sizeof(strlen(word)); 应该是:

malloc(sizeof(*w) + 1 + strlen(word));

许多 C 库提供了一个扩展来检索由 malloc()calloc()realloc() 等从堆中分配的块的大小。以下是其中一些:

  • BSD 系统具有:

     #include <malloc/malloc.h>
    
     size_t malloc_size(const void *ptr);
    

    malloc_size() 函数返回支持 ptr 指向的分配的内存块的大小。内存块大小始终至少与它支持的分配一样大,也可能更大。

    size_t malloc_good_size(size_t size);
    

    malloc_good_size() 函数将 size 向上舍入为分配器实现无需添加任何填充即可分配的值;然后返回该四舍五入的值。

  • GNU libC 具有:

     #include <malloc.h>
    
     size_t malloc_usable_size (void *ptr);
    

    malloc_usable_size() 函数返回 ptr 指向的块中可用字节数,一个指向由 ma​​lloc(3) 分配的内存块的指针或一个相关功能。

    malloc_usable_size() 返回 ptr 指向的已分配内存块中的可用字节数。如果 ptrNULL,则返回 0