0

我有一段代码如下,它们有什么区别?第一个,结构的buf元素地址比结构的地址大4,而第二个不是。

第一的

#include <stdio.h>

typedef struct A
{
    int i;
    char buf[];  //Here
}A;

int main()
{
    A *pa = malloc(sizeof(A));
    char *p = malloc(13);
    memcpy(p, "helloworld", 10);
    memcpy(pa->buf, p, 13);

    printf("%x %x %d %s\n", pa->buf, pa, (char *)pa->buf - (char *)pa, pa->buf);
}

第二

typedef struct A
{
    int i;
    char *buf; //Here
}A;
4

2 回答 2

6

第一个是 C99 的“灵活数组成员”。第二个是当您没有 C99 或更高版本时的可靠后备。

使用灵活的数组成员,您可以为数组分配所需的空间以及主结构:

A *pa = malloc(sizeof(A) + strlen(string) + 1);

pa->i = index;
strcpy(pa->buf, string);

...use pa...

free(pa);

就内存分配而言,buf成员没有大小(所以sizeof(A) == sizeof(int)除非由于数组对齐而存在填充问题——例如,如果你有一个灵活的数组double)。

替代方案需要两个分配(和两个版本),或者在设置中需要注意:

typedef struct A2
{
    int   i;
    char *buf;
} A2;

A2 *pa2 = malloc(sizeof(A2));
pa2->buff = strdup(string);

...use pa2...

free(pa2->buff);
free(pa2);

或者:

A2 *pa2 = malloc(sizeof(A2) + strlen(string) + 1);
pa2->buff = (char *)pa2 + sizeof(A2);

...use pa2...

free(pa2);

请注意,使用 A2 需要更多内存,无论是指针大小(单次分配),还是指针大小和第二次内存分配的开销(双重分配)。

你有时会看到一些被称为“struct hack”的东西正在使用中;这早于 C99 标准,并且已被灵活的数组成员淘汰。代码如下:

typedef struct A3
{
    int  i;
    char buf[1];
} A3;

A3 *pa3 = malloc(sizeof(A3) + strlen(string) + 1);
strcpy(pa3->buf, string);

这和灵活的数组成员差不多,但结构更大。在示例中,在大多数机器上,该结构的A3长度为 8 个字节(而不是 4 个字节A)。

GCC 对零长度数组有一些支持;您可能会看到数组维度为 0 的 struct hack。这对于任何不模仿 GCC 的编译器都是不可移植的。

它被称为“struct hack”,因为语言标准不能保证它是可移植的(因为您访问的是声明数组的边界之外)。然而,从经验上看,它“一直有效”并且可能会继续这样做。尽管如此,您应该优先使用灵活的数组成员而不是 struct hack。


ISO/IEC 9899:2011 §6.7.2.1 结构和联合说明符

¶3结构或联合不应包含不完整或函数类型的成员(因此,结构不应包含自身的实例,但可能包含指向自身实例的指针),除了结构的最后一个成员具有多个命名成员可能具有不完整的数组类型;这样的结构(以及任何可能递归地包含此类结构的成员的联合)不应是结构的成员或数组的元素。

¶18 作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活数组成员。在大多数情况下,灵活数组成员被忽略。特别是,结构的大小就像省略了柔性数组成员一样,只是它可能具有比省略所暗示的更多的尾随填充。然而,当一个.(或->) 运算符的左操作数是(指向)具有灵活数组成员的结构,右操作数命名该成员,它的行为就好像该成员被替换为最长的数组(具有相同的元素类型),不会使结构大于被访问的对象;数组的偏移量应保持灵活数组成员的偏移量,即使这与替换数组的偏移量不同。如果这个数组没有元素,它的行为就好像它有一个元素,但如果尝试访问该元素或生成一个越过它的指针,则行为是不确定的。

于 2012-12-10T16:02:23.880 回答
1
struct A {
    int i;
    char buf[];
};

不为数组指向数组的指针保留任何空间。这说明了一个数组可以直接跟随 的主体A并通过 来访问buf,如下所示:

struct A *a = malloc(sizeof(*a) + 6);
strcpy(a->buf, "hello");
assert(a->buf[0] == 'h');
assert(a->buf[5] == '\0';

a注意我为“hello”和 nul 终止符保留了 6 个字节。

指针形式使用间接(内存可以是连续的,但这既不依赖也不需要)

struct B {
    int i;
    char *buf;
};

/* requiring two allocations: */
struct B *b1 = malloc(sizeof(*b1));
b1->buf = strdup("hello");

/* or some pointer arithmetic */
struct B *b2 = malloc(sizeof(*b2) + 6);
b2->buf = (char *)((&b2->buf)+1);

第二个现在的布局与a上面相同,除了在整数和 char 数组之间有一个指针。

于 2012-12-10T16:09:10.473 回答