具有灵活数组成员的结构和具有指针成员的结构之间的区别

the difference between struct with flexible arrays members and struct with pointer members

我不再对灵活数组和指针作为结构成员之间的区别感到困惑。有人建议,struct with pointers 需要 malloc 两次。但是,请考虑以下代码:

    struct Vector {
        size_t size;
        double *data;
    };
    int len = 20;
    struct Vector* newVector = malloc(sizeof *newVector + len * sizeof*newVector->data);
    printf("%p\n",newVector->data);//print 0x0
    newVector->data =(double*)((char*)newVector + sizeof*newVector);
    // do sth
    free(newVector);

我发现不一样的是Vector的数据成员地址没有定义。程序员需要转换才能“找到”准确的地址。但是,如果将 Vector 定义为:

    struct Vector {
        size_t size;
        double data[];
    };

那么数据的地址就定义好了

我想知道像这样用指针 malloc struct 是否安全和能够,以及程序员在使用带指针的 struct 时 malloc 两次的确切原因是什么。

区别在于结构的存储方式。在第一个示例中,您 over-allocate 内存但这并不神奇地意味着 data 指针被设置为指向该内存。它在 malloc 之后的值实际上是不确定的,所以你不能可靠地打印它。

当然,您可以将该指针设置为指向超出结构本身分配的部分,但这意味着访问速度可能会变慢,因为您每次都需要通过指针。您还可以将指针本身分配为额外的 space (并且可能因此而额外填充),而在灵活的数组成员中 sizeof 不计算灵活的数组成员。你的第一个设计总体上比灵活的版本要麻烦得多,但除此之外 well-defined.

人们在使用带指针的结构时 malloc 两次的原因可能是他们不知道灵活的数组成员或使用 C90,或者代码不是 performance-critical 而他们只是不关心碎片化分配带来的开销

I am wondering whether it is safe and able to malloc struct with pointers like this, and what is the exactly reason programmers malloc twice when using struct with pointers.

如果只使用一次指针方法和malloc,在计算中需要额外注意一件事情:alignment.

让我们向结构中添加一个额外字段:

struct Vector {
    size_t size;
    uint32_t extra;        
    double *data;
};

假设我们在每个字段为 4 字节的系统上,结构上没有尾部填充且总大小为 12 字节。我们还假设 double 是 8 个字节并且需要对齐到 8 个字节。

现在有一个问题:表达式(char*)newVector + sizeof*newVector不再给出可被8整除的地址。需要在结构和数据之间手动填充4个字节。这使得 malloc 大小计算和数据指针偏移量计算变得复杂。

所以您看到 1 个 malloc 指针版本较少的主要原因是 更难正确 。使用指针和 2 个 mallocs,或灵活的数组成员,编译器负责必要的对齐计算和填充,因此您不必这样做。