3

我写了一个这样的动态数组:

#include <stdlib.h>

typedef struct {
    size_t capacity;
    size_t len;
} __dynarray_header;

void* dynarray_new() {
    __dynarray_header* header = malloc(sizeof(__dynarray_header));
    header->capacity = 0;
    header->len = 0;
    return header + 1;
}

可以通过[]操作访问动态数组。调整大小时,我可以__dynarray_header*)array - 1用来检索容量和长度信息。

这个想法在小测试中有效。然而,GCC 警告要打破严格的混叠。

我还发现了一些没有-fno-strict-aliasing编译器选项(带-O3优化)的大型项目段错误。

我知道什么是严格混叠,以及为什么我的代码会破坏严格混叠。

我的问题是:有没有比我上面展示的更好的方法来实现支持[]操作和动态调整大小的动态数组?

额外的:

使用此动态数组的演示程序:

int* arr = dynarray_new();
arr = dynarray_resize(sizeof(int) * 2);
arr[0] = 1;
arr[1] = 2;
arr = dynarray_resize(sizeof(int) * 4);
arr[2] = 3;
arr[3] = 4;
dynarray_free(arr);
4

2 回答 2

1

C 标准为这种事情预见的技术是灵活的数组,正如已经提到的:

typedef struct {
    size_t capacity;
    size_t len;
    unsigned char data[];
} dynarray_header;

如果您分配(或重新分配)struct具有足够空间的此类,您可以data像访问任何unsigned char数组一样访问该元素。chartypes 可以别名任何其他数据类型,所以你不会有问题。

如果您的编译器不支持灵活数组,只需[1]在其中放一个 for data

顺便说一句,以下划线开头的名称在文件范围内保留,您不应该使用这些。

于 2013-07-02T05:21:41.253 回答
0

提供的主要优化-fstrict-aliasing是在大多数情况下foo *可以任意移动对的引用。bar *您看到的段错误可能是由于引用在free某处移过类型操作。

虽然这感觉有点脏,但您可以通过在结构中添加预期数组元素类型的联合来使其在 C89 下工作,例如:

typedef struct {
    size_t capacity;
    size_t len;
    union {
        int i;
        double d;
        my_type mt;
        etc e;
        /* add additional types here. */
    } array_head;
} __dynarray_header;

然后,不是返回,而是header + 1返回(void *)&(header->array_head)

现在,即使使用严格的别名,编译器也更有可能考虑一个指向__dynarray_header可能别名指向该联合中任何内容的指针的指针,除非这些指针也是restrict- 限定的。(我假设对于您的用例,它们不是,至少在触发段错误的上下文中。)

仍然……正如丹尼斯·里奇所说,这似乎是“在实施方面毫无根据的亲密关系”。或者,换句话说,黑客。祝你好运!

(编辑:正如上面的 Carl 提醒我的,在 C99 中您可以使用灵活的数组成员。我没有使用它们,只是因为 C99 支持似乎不是我使用的 C 编译器的默认设置。这是 IBM 的参考:http: //pic.dhe.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Frzarg%2Fflexible.htm )

于 2013-07-02T04:39:12.500 回答