这两种实现有何不同:
struct queue {
int a;
int b;
q_info *array;
};
并且
struct queue {
int a;
int b;
q_info array[0];
};
这两种实现有何不同:
struct queue {
int a;
int b;
q_info *array;
};
struct queue {
int a;
int b;
q_info array[0];
};
第二个struct
没有使用零元素数组——这是在C99之前制作灵活数组成员的技巧。区别在于,在第一个片段中,您需要两个malloc
——一个为struct
,另一个为array
;而在第二个片段中,您可以在单个malloc
中完成两者:
size_t num_entries = 100;
struct queue *myQueue = malloc(sizeof(struct queue)+sizeof(q_info)*num_entries);
代替
size_t num_entries = 100;
struct queue *myQueue = malloc(sizeof(struct queue));
myQueue->array = malloc(sizeof(q_info)*num_entries);
这样可以减少dealloc次数,提供更好的引用局部性,并且还可以节省一个指针的空间。
从C99开始,您可以在数组成员声明中省略零:
struct queue {
int a;
int b;
q_info array[];
};
以下是完全不同的两个东西:
人们这样做的原因是它更加节省空间。你只需过度分配结构体需要的内存,然后假装数组比声明的元素多 - 编译器不会介意(通常)。
这也意味着你少了一个要解引用的指针,并且你可以为结构体和数组分配和释放内存。
显然,这个技巧只适用于数组是结构体中的最后一个元素时。
在第一个中,实际上在struct queue
中分配了一个指针,并且sizeof(struct queue) == 2 * sizeof(int) + sizeof(q_info*)
在第二个中,实际上没有指针或任何名为array
的东西存在于struct queue
中,而sizeof(struct queue) == 2 * sizeof(int)
。这被称为一种巧妙地引用数据的技巧,使用array
可以方便地在之前或之后引用数据。我在实现内存分配器时使用了这个技巧。
struct queue
的大小更多的内存(例如malloc(sizeof(struct queue) + sizeof(q_info) * 10)
),以便拥有一个连续的内存区域可供使用。然后该数组将成为已分配内存的一部分,对于上述例子的分配,它包含了十个q_info
条目。queue
结构体,一次用于array
成员。当然,你还需要调用两次free
函数,一次用于array
指针,一次用于结构体。q_info array[0];
由于自动转换,它会衰减为指针。但是,它是不可分配的。你不能说
array = <some address of an object>;
之后。
q_info array[0];
做什么聪明的事情? - Stephane RollandT array[0]
是未定义行为。 - user529758some_type some_array[];
来达到同样的目的。在此之前,通常会使用 [1],稍后再通过sizeof
进行操作。 - keltar