以下结构的大小是多少?
struct employee
{
int emp_id;
int name_len;
char name[0];
};
4 + 4 + 0 = 8个字节。
那“名称[0]”的大小呢?在gcc中,当我们创建长度为零的数组时,它被视为不完整类型的数组,这就是gcc将其大小报告为“ 0”字节的原因。这种技术被称为“ Stuct Hack”。当我们在结构内部创建零长度的数组时,它必须是(并且仅是)结构的最后一个成员。不久,我们将看到如何使用它。
“ Struct Hack”技术用于在结构中创建可变长度的成员。在上述结构中,“名称”的字符串长度不是固定的,因此我们可以将“名称”用作可变长度数组。
让我们看下面的内存分配。
struct employee *e = malloc(sizeof(*e) + sizeof(char) * 128);
相当于
struct employee
{
int emp_id;
int name_len;
char name[128]; /* character array of size 128 */
};
和下面的内存分配
struct employee *e = malloc(sizeof(*e) + sizeof(char) * 1024);
相当于
struct employee
{
int emp_id;
int name_len;
char name[1024]; /* character array of size 1024 */
};
注意:由于名称是字符数组,因此在malloc中而不是“ sizeof(char)* 128”中,我们可以直接使用“ 128”。 sizeof用于避免混淆。
现在,我们可以使用与指针相同的“名称”。例如
e->emp_id = 100;
e->name_len = strlen("Geeks For Geeks");
strncpy(e->name, "Geeks For Geeks", e->name_len);
当我们如上所述分配内存时,编译器将分配用于存储“ emp_id”和“ name_len”的内存,以及用于存储“ name”的连续内存。当我们使用这种技术时,gcc保证“名称”将获得连续的内存。
显然还有其他方法可以解决问题,一种是可以使用字符指针。但是不能保证字符指针将获得连续的内存,我们可以利用此连续的内存。例如,通过使用此技术,我们可以使用单个malloc和free调用来分配和取消分配内存(因为内存具有传染性)。这样做的另一个优点是,假设我们要写入数据,则可以使用单个“ write()”调用来写入整个数据。例如
write(fd, e, sizeof(*e) + name_len); /* write emp_id + name_len + name */
如果使用字符指针,则需要2个write调用来写入数据。例如
write(fd, e, sizeof(*e)); /* write emp_id + name_len */
write(fd, e->name, e->name_len); /* write name */
注意:在C99中,有一个称为“弹性数组成员”的功能,其功能与“ Struct Hack”相同